replace common qcom sources with samsung ones

This commit is contained in:
SaschaNes
2025-08-12 22:13:00 +02:00
parent ba24dcded9
commit 6f7753de11
5682 changed files with 2450203 additions and 103634 deletions

View File

@@ -0,0 +1,84 @@
// Temporarily disable fst-manager service as part of disabling WIGIG modules
/*
PKG_CONFIG = ["pkg-config"]
LOCAL_INCLUDES = ["."]
LOCAL_INCLUDES += ["hidl"]
LOCAL_INCLUDES += ["external"]
LOCAL_INCLUDES += ["external/common"]
LOCAL_INCLUDES += ["external/fst"]
LOCAL_INCLUDES += ["external/utils"]
LOCAL_INCLUDES += ["external/inih"]
// The iproute includes used for a correct linux/pkt_sched.h
INCLUDES = ["external/iproute2/include"]
INCLUDES += ["external/libnl/include"]
OBJS = ["fst_mux_bonding.c"]
OBJS += ["fst_manager.c"]
OBJS += ["fst_tc.c"]
OBJS += ["fst_ctrl.c"]
OBJS += ["main.c"]
OBJS += ["fst_cfgmgr.c"]
OBJS += ["fst_ini_conf.c"]
OBJS += ["fst_rateupg.c"]
OBJS += ["fst_capconfigstore.cpp"]
OBJS += ["fst_tpoll.c"]
OBJS += ["hidl/fst_hidl.cpp"]
OBJS += ["hidl/hidl_manager.cpp"]
OBJS += ["hidl/FstManager.cpp"]
OBJS += ["hidl/FstGroup.cpp"]
OBJS += ["external/wpa_ctrl.c"]
OBJS += ["external/eloop.c"]
OBJS += ["external/common.c"]
OBJS += ["external/os_unix.c"]
OBJS += ["external/wpa_debug.c"]
OBJS += ["external/fst_ctrl_aux.c"]
OBJS += ["external/inih/ini.c"]
L_CFLAGS = [
"-DCONFIG_CTRL_IFACE",
"-DCONFIG_CTRL_IFACE_UNIX",
"-DCONFIG_FST",
"-DCONFIG_LIBNL20",
"-DANDROID",
]
L_CFLAGS += ["-DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/sockets\""]
L_CFLAGS += ["-DDEFAULT_HAPD_CLI_DIR=\"/data/vendor/wifi/hostapd\""]
L_CFLAGS += ["-DDEFAULT_WPAS_CLI_DIR=\"\""]
L_CFLAGS += ["-DCONFIG_ANDROID_LOG"]
L_CFLAGS += ["-DANDROID_LOG_NAME=\"fstman\""]
// Disable unused parameter warnings
L_CFLAGS += ["-Wno-unused-parameter"]
prebuilt_etc {
name: "fstman.ini",
src: "fstman.ini",
sub_dir: "wifi",
proprietary: true,
}
cc_binary {
name: "fstman",
init_rc: ["vendor.qti.hardware.fstman@1.0-service.rc"],
vendor: true,
shared_libs: [
"libnl",
"libcutils",
"liblog",
"libutils",
"libhidlbase",
"vendor.qti.hardware.capabilityconfigstore@1.0",
"vendor.qti.hardware.fstman@1.0",
],
header_libs: ["libcutils_headers"],
cflags: L_CFLAGS,
srcs: OBJS,
include_dirs: INCLUDES,
local_include_dirs: LOCAL_INCLUDES,
}
*/

View File

@@ -0,0 +1,146 @@
-include $(TOPDIR)/rules.mk
CFLAGS := -Wall -g -MMD
LDFLAGS :=
LIBS :=
LOCAL_CFLAGS :=
EXTERNAL_CFLAGS :=
ifeq ($(CONFIG_TARGET_BOARD),"ipq806x")
is_ipq806x = 1
endif
ifeq ($(is_ipq806x), 1)
ifneq ($(strip $(TOOLPREFIX)),)
export CROSS:=$(TOOLPREFIX)
endif
ifndef INSTALL_ROOT
INSTALL_ROOT= $(FSTMANDIR)/install
endif
export CC = $(CROSS)gcc
CFLAGS += -L$(INSTALL_ROOT)/lib
endif
external_srcs :=
ifeq ($(is_ipq806x), 1)
CONFIG_MUX_L2DA:=1
endif
PKG_CONFIG := pkg-config
EXTERNAL_SRC_DIR := external
progs := fstman
ifndef CONFIG_MUX_L2DA
FST_MUX_SRCS=fst_mux_bonding.c fst_tc.c
else
FST_MUX_SRCS=fst_mux_l2da.c
endif
local_srcs := $(FST_MUX_SRCS) \
fst_manager.c
LOCAL_CFLAGS += -I$(EXTERNAL_SRC_DIR)/ -I$(EXTERNAL_SRC_DIR)/inih
EXTERNAL_CFLAGS += $(addprefix -I,$(sort $(dir $(wildcard $(EXTERNAL_SRC_DIR)/*/))))
LOCAL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
ifeq ($(is_ipq806x), 1)
LIBS += -lnl-3
else
LIBS += $(shell $(PKG_CONFIG) --libs libnl-3.0)
endif
ifndef CONFIG_DBUS
external_srcs += \
$(EXTERNAL_SRC_DIR)/wpa_ctrl.c \
$(EXTERNAL_SRC_DIR)/eloop.c \
$(EXTERNAL_SRC_DIR)/common.c \
$(EXTERNAL_SRC_DIR)/os_unix.c \
$(EXTERNAL_SRC_DIR)/wpa_debug.c \
$(EXTERNAL_SRC_DIR)/fst_ctrl_aux.c \
$(EXTERNAL_SRC_DIR)/inih/ini.c
EXTERNAL_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX -DCONFIG_FST
EXTERNAL_CFLAGS += -DCONFIG_DEBUG_FILE
local_srcs += fst_ctrl.c fst_cfgmgr.c fst_ini_conf.c main.c fst_rateupg.c fst_tpoll.c fst_capconfigstore.c
else
LOCAL_CFLAGS += \
$(shell $(PKG_CONFIG) --cflags glib-2.0) \
$(shell $(PKG_CONFIG) --cflags gio-2.0) \
-DCONFIG_DBUS
LIBS += \
$(shell $(PKG_CONFIG) --libs glib-2.0) \
$(shell $(PKG_CONFIG) --libs gio-2.0)
local_srcs += fst_ctrl_dbus.c main_dbus.c
external_srcs += \
$(EXTERNAL_SRC_DIR)/os_unix.c \
$(EXTERNAL_SRC_DIR)/fst_ctrl_aux.c
endif
ifeq ($(is_ipq806x), 1)
# What we build by default:
ALL = $(progs)
endif
local_objs :=$(local_srcs:.c=.o)
external_objs := $(external_srcs:.c=.o)
all_objs :=$(local_objs) $(external_objs)
ifeq ($(is_ipq806x), 1)
all prod prof: $(progs) install
else
all prod prof: $(progs)
endif
fstman: $(all_objs)
prod prof: CFLAGS += -O2
prof: CFLAGS += -pg
prod: strip
$(all_objs): %.o: %.c
$(local_objs):
$(CC) $(CFLAGS) $(LOCAL_CFLAGS) -o $@ -c $<
$(external_objs):
$(CC) $(CFLAGS) $(EXTERNAL_CFLAGS) -o $@ -c $<
$(progs): %:
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
strip:
strip $(progs)
# Doing installation (see comments at top of this file)
install:
ifeq ($(is_ipq806x), 1)
mkdir -p $(INSTALL_ROOT)/usr/sbin/
cp -a -f $(ALL) $(INSTALL_ROOT)/usr/sbin/
@echo Installed outputs from `pwd`
endif
clean:
ifeq ($(is_ipq806x), 1)
rm -rf install/usr/sbin/fstman
endif
$(RM) $(all_objs) $(progs) $(all_objs:%.o=%.d)
echo:
@echo $(progs) $(local_srcs) $(all_objs) $(all_objs:%.o=%.d)
-include $(all_objs:%.o=%.d)

View File

@@ -0,0 +1,978 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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;
}
static const char * hwaddr_parse(const char *txt, u8 *addr)
{
size_t i;
for (i = 0; i < ETH_ALEN; i++) {
int a;
a = hex2byte(txt);
if (a < 0)
return NULL;
txt += 2;
addr[i] = a;
if (i < ETH_ALEN - 1 && *txt++ != ':')
return NULL;
}
return txt;
}
/**
* 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)
{
return hwaddr_parse(txt, addr) ? 0 : -1;
}
/**
* hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
* @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
* @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
* @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
* @maskable: Flag to indicate whether a mask is allowed
* Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
*/
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
{
const char *r;
/* parse address part */
r = hwaddr_parse(txt, addr);
if (!r)
return -1;
/* check for optional mask */
if (*r == '\0' || isspace(*r)) {
/* no mask specified, assume default */
os_memset(mask, 0xff, ETH_ALEN);
} else if (maskable && *r == '/') {
/* mask specified and allowed */
r = hwaddr_parse(r + 1, mask);
/* parser error? */
if (!r)
return -1;
} else {
/* mask specified but not allowed or trailing garbage */
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;
}
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
{
size_t i;
int print_mask = 0;
int res;
for (i = 0; i < ETH_ALEN; i++) {
if (mask[i] != 0xff) {
print_mask = 1;
break;
}
}
if (print_mask)
res = os_snprintf(buf, len, MACSTR "/" MACSTR,
MAC2STR(addr), MAC2STR(mask));
else
res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
if (os_snprintf_error(len, res))
return -1;
return res;
}
/**
* 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);
}
/**
* wpa_scnprintf - Simpler-to-use snprintf function
* @buf: Output buffer
* @size: Buffer size
* @fmt: format
*
* Simpler snprintf version that doesn't require further error checks - the
* return value only indicates how many bytes were actually written, excluding
* the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
*/
int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
int ret;
if (!size)
return 0;
va_start(ap, fmt);
ret = vsnprintf(buf, size, fmt, ap);
va_end(ap);
if (ret < 0)
return 0;
if ((size_t) ret >= size)
return size - 1;
return ret;
}
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 (os_snprintf_error(end - pos, ret)) {
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 */
void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
{
char *end = txt + maxlen;
size_t i;
for (i = 0; i < len; i++) {
if (txt + 4 >= end)
break;
switch (data[i]) {
case '\"':
*txt++ = '\\';
*txt++ = '\"';
break;
case '\\':
*txt++ = '\\';
*txt++ = '\\';
break;
case '\033':
*txt++ = '\\';
*txt++ = 'e';
break;
case '\n':
*txt++ = '\\';
*txt++ = 'n';
break;
case '\r':
*txt++ = '\\';
*txt++ = 'r';
break;
case '\t':
*txt++ = '\\';
*txt++ = 't';
break;
default:
if (data[i] >= 32 && data[i] <= 127) {
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\x%02x",
data[i]);
}
break;
}
}
*txt = '\0';
}
size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
{
const char *pos = str;
size_t len = 0;
int val;
while (*pos) {
if (len + 1 >= maxlen)
break;
switch (*pos) {
case '\\':
pos++;
switch (*pos) {
case '\\':
buf[len++] = '\\';
pos++;
break;
case '"':
buf[len++] = '"';
pos++;
break;
case 'n':
buf[len++] = '\n';
pos++;
break;
case 'r':
buf[len++] = '\r';
pos++;
break;
case 't':
buf[len++] = '\t';
pos++;
break;
case 'e':
buf[len++] = '\033';
pos++;
break;
case 'x':
pos++;
val = hex2byte(pos);
if (val < 0) {
val = hex2num(*pos);
if (val < 0)
break;
buf[len++] = val;
pos++;
} else {
buf[len++] = val;
pos += 2;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
val = *pos++ - '0';
if (*pos >= '0' && *pos <= '7')
val = val * 8 + (*pos++ - '0');
if (*pos >= '0' && *pos <= '7')
val = val * 8 + (*pos++ - '0');
buf[len++] = val;
break;
default:
break;
}
break;
default:
buf[len++] = *pos++;
break;
}
}
if (maxlen > len)
buf[len] = '\0';
return len;
}
/**
* 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[32 * 4 + 1];
if (ssid == NULL) {
ssid_txt[0] = '\0';
return ssid_txt;
}
printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
return ssid_txt;
}
void * __hide_aliasing_typecast(void *foo)
{
return foo;
}
char * wpa_config_parse_string(const char *value, size_t *len)
{
if (*value == '"') {
const char *pos;
char *str;
value++;
pos = os_strrchr(value, '"');
if (pos == NULL || pos[1] != '\0')
return NULL;
*len = pos - value;
str = dup_binstr(value, *len);
if (str == NULL)
return NULL;
return str;
} else if (*value == 'P' && value[1] == '"') {
const char *pos;
char *tstr, *str;
size_t tlen;
value += 2;
pos = os_strrchr(value, '"');
if (pos == NULL || pos[1] != '\0')
return NULL;
tlen = pos - value;
tstr = dup_binstr(value, tlen);
if (tstr == NULL)
return NULL;
str = os_malloc(tlen + 1);
if (str == NULL) {
os_free(tstr);
return NULL;
}
*len = printf_decode((u8 *) str, tlen + 1, tstr);
os_free(tstr);
return str;
} else {
u8 *str;
size_t tlen, hlen = os_strlen(value);
if (hlen & 1)
return NULL;
tlen = hlen / 2;
str = os_malloc(tlen + 1);
if (str == NULL)
return NULL;
if (hexstr2bin(value, str, tlen)) {
os_free(str);
return NULL;
}
str[tlen] = '\0';
*len = tlen;
return (char *) str;
}
}
int is_hex(const u8 *data, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (data[i] < 32 || data[i] >= 127)
return 1;
}
return 0;
}
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
{
size_t len = 0;
os_memset(res, 0, res_len);
if (src1) {
if (src1_len >= res_len) {
os_memcpy(res, src1, res_len);
return res_len;
}
os_memcpy(res, src1, src1_len);
len += src1_len;
}
if (src2) {
if (len + src2_len >= res_len) {
os_memcpy(res + len, src2, res_len - len);
return res_len;
}
os_memcpy(res + len, src2, src2_len);
len += src2_len;
}
return len;
}
char * dup_binstr(const void *src, size_t len)
{
char *res;
if (src == NULL)
return NULL;
res = os_malloc(len + 1);
if (res == NULL)
return NULL;
os_memcpy(res, src, len);
res[len] = '\0';
return res;
}
int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
{
struct wpa_freq_range *freq = NULL, *n;
unsigned int count = 0;
const char *pos, *pos2, *pos3;
/*
* Comma separated list of frequency ranges.
* For example: 2412-2432,2462,5000-6000
*/
pos = value;
while (pos && pos[0]) {
n = os_realloc_array(freq, count + 1,
sizeof(struct wpa_freq_range));
if (n == NULL) {
os_free(freq);
return -1;
}
freq = n;
freq[count].min = atoi(pos);
pos2 = os_strchr(pos, '-');
pos3 = os_strchr(pos, ',');
if (pos2 && (!pos3 || pos2 < pos3)) {
pos2++;
freq[count].max = atoi(pos2);
} else
freq[count].max = freq[count].min;
pos = pos3;
if (pos)
pos++;
count++;
}
os_free(res->range);
res->range = freq;
res->num = count;
return 0;
}
int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq)
{
unsigned int i;
if (list == NULL)
return 0;
for (i = 0; i < list->num; i++) {
if (freq >= list->range[i].min && freq <= list->range[i].max)
return 1;
}
return 0;
}
char * freq_range_list_str(const struct wpa_freq_range_list *list)
{
char *buf, *pos, *end;
size_t maxlen;
unsigned int i;
int res;
if (list->num == 0)
return NULL;
maxlen = list->num * 30;
buf = os_malloc(maxlen);
if (buf == NULL)
return NULL;
pos = buf;
end = buf + maxlen;
for (i = 0; i < list->num; i++) {
struct wpa_freq_range *range = &list->range[i];
if (range->min == range->max)
res = os_snprintf(pos, end - pos, "%s%u",
i == 0 ? "" : ",", range->min);
else
res = os_snprintf(pos, end - pos, "%s%u-%u",
i == 0 ? "" : ",",
range->min, range->max);
if (os_snprintf_error(end - pos, res)) {
os_free(buf);
return NULL;
}
pos += res;
}
return buf;
}
int int_array_len(const int *a)
{
int i;
for (i = 0; a && a[i]; i++)
;
return i;
}
void int_array_concat(int **res, const int *a)
{
int reslen, alen, i;
int *n;
reslen = int_array_len(*res);
alen = int_array_len(a);
n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
*res = NULL;
return;
}
for (i = 0; i <= alen; i++)
n[reslen + i] = a[i];
*res = n;
}
static int freq_cmp(const void *a, const void *b)
{
int _a = *(int *) a;
int _b = *(int *) b;
if (_a == 0)
return 1;
if (_b == 0)
return -1;
return _a - _b;
}
void int_array_sort_unique(int *a)
{
int alen;
int i, j;
if (a == NULL)
return;
alen = int_array_len(a);
qsort(a, alen, sizeof(int), freq_cmp);
i = 0;
j = 1;
while (a[i] && a[j]) {
if (a[i] == a[j]) {
j++;
continue;
}
a[++i] = a[j++];
}
if (a[i])
i++;
a[i] = 0;
}
void int_array_add_unique(int **res, int a)
{
int reslen;
int *n;
for (reslen = 0; *res && (*res)[reslen]; reslen++) {
if ((*res)[reslen] == a)
return; /* already in the list */
}
n = os_realloc_array(*res, reslen + 2, sizeof(int));
if (n == NULL) {
os_free(*res);
*res = NULL;
return;
}
n[reslen] = a;
n[reslen + 1] = 0;
*res = n;
}
void str_clear_free(char *str)
{
if (str) {
size_t len = os_strlen(str);
os_memset(str, 0, len);
os_free(str);
}
}
void bin_clear_free(void *bin, size_t len)
{
if (bin) {
os_memset(bin, 0, len);
os_free(bin);
}
}
int random_mac_addr(u8 *addr)
{
if (os_get_random(addr, ETH_ALEN) < 0)
return -1;
addr[0] &= 0xfe; /* unicast */
addr[0] |= 0x02; /* locally administered */
return 0;
}
int random_mac_addr_keep_oui(u8 *addr)
{
if (os_get_random(addr + 3, 3) < 0)
return -1;
addr[0] &= 0xfe; /* unicast */
addr[0] |= 0x02; /* locally administered */
return 0;
}
/**
* str_token - Get next token from a string
* @buf: String to tokenize. Note that the string might be modified.
* @delim: String of delimiters
* @context: Pointer to save our context. Should be initialized with
* NULL on the first call, and passed for any further call.
* Returns: The next token, NULL if there are no more valid tokens.
*/
char * str_token(char *str, const char *delim, char **context)
{
char *end, *pos = str;
if (*context)
pos = *context;
while (*pos && os_strchr(delim, *pos))
pos++;
if (!*pos)
return NULL;
end = pos + 1;
while (*end && !os_strchr(delim, *end))
end++;
if (*end)
*end++ = '\0';
*context = end;
return pos;
}

View File

@@ -0,0 +1,329 @@
/*
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DEFS_H
#define DEFS_H
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#define WPA_CIPHER_GCMP BIT(6)
#define WPA_CIPHER_SMS4 BIT(7)
#define WPA_CIPHER_GCMP_256 BIT(8)
#define WPA_CIPHER_CCMP_256 BIT(9)
#define WPA_CIPHER_BIP_GMAC_128 BIT(11)
#define WPA_CIPHER_BIP_GMAC_256 BIT(12)
#define WPA_CIPHER_BIP_CMAC_256 BIT(13)
#define WPA_CIPHER_GTK_NOT_USED BIT(14)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
#define WPA_KEY_MGMT_NONE BIT(2)
#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
#define WPA_KEY_MGMT_WPA_NONE BIT(4)
#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
#define WPA_KEY_MGMT_FT_PSK BIT(6)
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
#define WPA_KEY_MGMT_SAE BIT(10)
#define WPA_KEY_MGMT_FT_SAE BIT(11)
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_ft(int akm)
{
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sae(int akm)
{
return !!(akm & (WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sha256(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SUITE_B));
}
static inline int wpa_key_mgmt_sha384(int akm)
{
return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
}
static inline int wpa_key_mgmt_suite_b(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa(int akm)
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm) ||
wpa_key_mgmt_sae(akm);
}
static inline int wpa_key_mgmt_wpa_any(int akm)
{
return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
}
static inline int wpa_key_mgmt_cckm(int akm)
{
return akm == WPA_KEY_MGMT_CCKM;
}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_PROTO_WAPI BIT(2)
#define WPA_PROTO_OSEN BIT(3)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
#define WPA_AUTH_ALG_SAE BIT(4)
enum wpa_alg {
WPA_ALG_NONE,
WPA_ALG_WEP,
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
WPA_ALG_PMK,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK,
WPA_ALG_GCMP_256,
WPA_ALG_CCMP_256,
WPA_ALG_BIP_GMAC_128,
WPA_ALG_BIP_GMAC_256,
WPA_ALG_BIP_CMAC_256
};
/**
* enum wpa_states - wpa_supplicant state
*
* These enumeration values are used to indicate the current wpa_supplicant
* state (wpa_s->wpa_state). The current state can be retrieved with
* wpa_supplicant_get_state() function and the state can be changed by calling
* wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
* wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
* to access the state variable.
*/
enum wpa_states {
/**
* WPA_DISCONNECTED - Disconnected state
*
* This state indicates that client is not associated, but is likely to
* start looking for an access point. This state is entered when a
* connection is lost.
*/
WPA_DISCONNECTED,
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
* This stat eis entered if the network interface is disabled, e.g.,
* due to rfkill. wpa_supplicant refuses any new operations that would
* use the radio until the interface has been enabled.
*/
WPA_INTERFACE_DISABLED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
* This state is entered if there are no enabled networks in the
* configuration. wpa_supplicant is not trying to associate with a new
* network and external interaction (e.g., ctrl_iface call to add or
* enable a network) is needed to start association.
*/
WPA_INACTIVE,
/**
* WPA_SCANNING - Scanning for a network
*
* This state is entered when wpa_supplicant starts scanning for a
* network.
*/
WPA_SCANNING,
/**
* WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to authenticate with and the driver is configured to try to
* authenticate with this BSS. This state is used only with drivers
* that use wpa_supplicant as the SME.
*/
WPA_AUTHENTICATING,
/**
* WPA_ASSOCIATING - Trying to associate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to associate with and the driver is configured to try to associate
* with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
* state is entered when the driver is configured to try to associate
* with a network using the configured SSID and security policy.
*/
WPA_ASSOCIATING,
/**
* WPA_ASSOCIATED - Association completed
*
* This state is entered when the driver reports that association has
* been successfully completed with an AP. If IEEE 802.1X is used
* (with or without WPA/WPA2), wpa_supplicant remains in this state
* until the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_ASSOCIATED,
/**
* WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
*
* This state is entered when WPA/WPA2 4-Way Handshake is started. In
* case of WPA-PSK, this happens when receiving the first EAPOL-Key
* frame after association. In case of WPA-EAP, this state is entered
* when the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_4WAY_HANDSHAKE,
/**
* WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
*
* This state is entered when 4-Way Key Handshake has been completed
* (i.e., when the supplicant sends out message 4/4) and when Group
* Key rekeying is started by the AP (i.e., when supplicant receives
* message 1/2).
*/
WPA_GROUP_HANDSHAKE,
/**
* WPA_COMPLETED - All authentication completed
*
* This state is entered when the full authentication process is
* completed. In case of WPA2, this happens when the 4-Way Handshake is
* successfully completed. With WPA, this state is entered after the
* Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
* completed after dynamic keys are received (or if not used, after
* the EAP authentication has been completed). With static WEP keys and
* plaintext connections, this state is entered when an association
* has been completed.
*
* This state indicates that the supplicant has completed its
* processing for the association phase and that data connection is
* fully configured.
*/
WPA_COMPLETED
};
#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
/**
* enum mfp_options - Management frame protection (IEEE 802.11w) options
*/
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
MGMT_FRAME_PROTECTION_REQUIRED = 2,
};
#define MGMT_FRAME_PROTECTION_DEFAULT 3
/**
* enum hostapd_hw_mode - Hardware mode
*/
enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
HOSTAPD_MODE_IEEE80211AD,
NUM_HOSTAPD_MODES
};
/**
* enum wpa_ctrl_req_type - Control interface request types
*/
enum wpa_ctrl_req_type {
WPA_CTRL_REQ_UNKNOWN,
WPA_CTRL_REQ_EAP_IDENTITY,
WPA_CTRL_REQ_EAP_PASSWORD,
WPA_CTRL_REQ_EAP_NEW_PASSWORD,
WPA_CTRL_REQ_EAP_PIN,
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
NUM_WPA_CTRL_REQS
};
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
enum mesh_plink_state {
PLINK_LISTEN = 1,
PLINK_OPEN_SENT,
PLINK_OPEN_RCVD,
PLINK_CNF_RCVD,
PLINK_ESTAB,
PLINK_HOLDING,
PLINK_BLOCKED,
};
#endif /* DEFS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,442 @@
/*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_CTRL_H
#define WPA_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
/* wpa_supplicant control interface - fixed message prefixes */
/** Interactive request for identity/password/pin */
#define WPA_CTRL_REQ "CTRL-REQ-"
/** Response to identity/password/pin request */
#define WPA_CTRL_RSP "CTRL-RSP-"
/* Event messages with fixed prefix */
/** Authentication completed successfully and data connection enabled */
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
/** Disconnected, data connection is not available */
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** Association rejected during connection attempt */
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
/** EAP-Request/Notification received */
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
/** EAP authentication started (EAP-Request/Identity received) */
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
/** EAP method proposed by the server */
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
/** EAP method selected */
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
/** EAP peer certificate alternative subject name component from TLS */
#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
/** Network block temporarily disabled (e.g., due to authentication failure) */
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
/** Temporarily disabled network block re-enabled */
#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
/** New scan started */
#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
/** Scan command failed */
#define WPA_EVENT_SCAN_FAILED "CTRL-EVENT-SCAN-FAILED "
/** wpa_supplicant state change */
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
/** Change in the signal level was reported by the driver */
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
/** Regulatory domain channel */
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
/** RSN IBSS 4-way handshakes completed with specified peer */
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
/** Notification of frequency conflict due to a concurrent operation.
*
* The indicated network is disabled and needs to be re-enabled before it can
* be used again.
*/
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** Frequency ranges that the driver recommends to avoid */
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
/** Available WPS AP with our address as authorized in scan results */
#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
/** Available WPS AP with recently selected PIN registrar found in scan results
*/
#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
/** Available WPS AP found in scan results */
#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
/** A new credential received */
#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
/** M2D received */
#define WPS_EVENT_M2D "WPS-M2D "
/** WPS registration failed after M2/M2D */
#define WPS_EVENT_FAIL "WPS-FAIL "
/** WPS registration completed successfully */
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
/** WPS enrollment attempt timed out and was terminated */
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
/* PBC mode was activated */
#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE "
/* PBC mode was disabled */
#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE "
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
/* WPS ER events */
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
/* WMM AC events */
#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
#define WMM_AC_EVENT_TSPEC_REMOVED "TSPEC-REMOVED "
#define WMM_AC_EVENT_TSPEC_REQ_FAILED "TSPEC-REQ-FAILED "
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
/** P2P device lost */
#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
/** A P2P device requested GO negotiation, but we were not ready to start the
* negotiation */
#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
/* parameters: <peer address> <PIN> */
#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
/* parameters: <peer address> <status> */
#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
/* parameters: <src addr> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
#define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO "
#define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT "
#define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT "
/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
/* Credential block added; parameters: <id> */
#define CRED_ADDED "CRED-ADDED "
/* Credential block modified; parameters: <id> <field> */
#define CRED_MODIFIED "CRED-MODIFIED "
/* Credential block removed; parameters: <id> */
#define CRED_REMOVED "CRED-REMOVED "
#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
/* parameters: <addr> <dialog_token> <freq> */
#define GAS_QUERY_START "GAS-QUERY-START "
/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
#define GAS_QUERY_DONE "GAS-QUERY-DONE "
/* parameters: <addr> <result> */
#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
#define RRM_EVENT_NEIGHBOR_REP_RXED "RRM-NEIGHBOR-REP-RECEIVED "
#define RRM_EVENT_NEIGHBOR_REP_FAILED "RRM-NEIGHBOR-REP-REQUEST-FAILED "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
#define AP_EVENT_ENABLED "AP-ENABLED "
#define AP_EVENT_DISABLED "AP-DISABLED "
#define INTERFACE_ENABLED "INTERFACE-ENABLED "
#define INTERFACE_DISABLED "INTERFACE-DISABLED "
#define ACS_EVENT_STARTED "ACS-STARTED "
#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
#define ACS_EVENT_FAILED "ACS-FAILED "
#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
#define DFS_EVENT_CAC_START "DFS-CAC-START "
#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
#define WPA_BSS_MASK_ID BIT(0)
#define WPA_BSS_MASK_BSSID BIT(1)
#define WPA_BSS_MASK_FREQ BIT(2)
#define WPA_BSS_MASK_BEACON_INT BIT(3)
#define WPA_BSS_MASK_CAPABILITIES BIT(4)
#define WPA_BSS_MASK_QUAL BIT(5)
#define WPA_BSS_MASK_NOISE BIT(6)
#define WPA_BSS_MASK_LEVEL BIT(7)
#define WPA_BSS_MASK_TSF BIT(8)
#define WPA_BSS_MASK_AGE BIT(9)
#define WPA_BSS_MASK_IE BIT(10)
#define WPA_BSS_MASK_FLAGS BIT(11)
#define WPA_BSS_MASK_SSID BIT(12)
#define WPA_BSS_MASK_WPS_SCAN BIT(13)
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
#define WPA_BSS_MASK_INTERNETW BIT(15)
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
#define WPA_BSS_MASK_DELIM BIT(17)
#define WPA_BSS_MASK_MESH_SCAN BIT(18)
#define WPA_BSS_MASK_FST BIT(19)
/* VENDOR_ELEM_* frame id values */
enum wpa_vendor_elem_frame {
VENDOR_ELEM_PROBE_REQ_P2P = 0,
VENDOR_ELEM_PROBE_RESP_P2P = 1,
VENDOR_ELEM_PROBE_RESP_P2P_GO = 2,
VENDOR_ELEM_BEACON_P2P_GO = 3,
VENDOR_ELEM_P2P_PD_REQ = 4,
VENDOR_ELEM_P2P_PD_RESP = 5,
VENDOR_ELEM_P2P_GO_NEG_REQ = 6,
VENDOR_ELEM_P2P_GO_NEG_RESP = 7,
VENDOR_ELEM_P2P_GO_NEG_CONF = 8,
VENDOR_ELEM_P2P_INV_REQ = 9,
VENDOR_ELEM_P2P_INV_RESP = 10,
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
VENDOR_ELEM_ASSOC_REQ = 13,
NUM_VENDOR_ELEM_FRAMES
};
/* wpa_supplicant/hostapd control interface access */
/**
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
* Returns: Pointer to abstract control interface data or %NULL on failure
*
* This function is used to open a control interface to wpa_supplicant/hostapd.
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
* is configured in wpa_supplicant/hostapd and other programs using the control
* interface need to use matching path configuration.
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
*
* This function is used to close a control interface.
*/
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
* @cmd: Command; usually, ASCII text, e.g., "PING"
* @cmd_len: Length of the cmd in bytes
* @reply: Buffer for the response
* @reply_len: Reply buffer length
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
* of the reply. This function will block for up to two seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
* msg_cb can be used to register a callback function that will be called for
* unsolicited messages received while waiting for the command response. These
* messages may be received if wpa_ctrl_request() is called at the same time as
* wpa_supplicant/hostapd is sending such a message. This can happen only if
* the program has used wpa_ctrl_attach() to register itself as a monitor for
* event messages. Alternatively to msg_cb, programs can register two control
* interface connections and use one of them for commands and the other one for
* receiving event messages, in other words, call wpa_ctrl_attach() only for
* the control interface connection that will be used for event messages.
*/
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
/**
* wpa_ctrl_attach - Register as an event monitor for the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function registers the control interface connection as a monitor for
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
* control interface connection starts receiving event messages that can be
* read with wpa_ctrl_recv().
*/
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_detach - Unregister event monitor from the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function unregisters the control interface connection as a monitor for
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
* wpa_ctrl_attach().
*/
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_recv - Receive a pending control interface message
* @ctrl: Control interface data from wpa_ctrl_open()
* @reply: Buffer for the message data
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
* This function will receive a pending control interface message. The received
* response will be written to reply and reply_len is set to the actual length
* of the reply.
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/**
* wpa_ctrl_pending - Check whether there are pending event messages
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
*
* This function will check whether there are any pending control interface
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
* register the control interface as an event monitor.
*/
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: File descriptor used for the connection
*
* This function can be used to get the file descriptor that is used for the
* control interface connection. The returned value can be used, e.g., with
* select() while waiting for multiple events.
*
* The returned file descriptor must not be used directly for sending or
* receiving packets; instead, the library functions wpa_ctrl_request() and
* wpa_ctrl_recv() must be used for this.
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
* may be left over from clients that were previously connected to
* wpa_supplicant. This keeps these files from being orphaned in the
* event of crashes that prevented them from being removed as part
* of the normal orderly shutdown.
*/
void wpa_ctrl_cleanup(void);
#endif /* ANDROID */
#ifdef CONFIG_CTRL_IFACE_UDP
/* Port range for multiple wpa_supplicant instances and multiple VIFs */
#define WPA_CTRL_IFACE_PORT 9877
#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef __cplusplus
}
#endif
#endif /* WPA_CTRL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
/*
* FST module - miscellaneous definitions
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef FST_MISC_H
#define FST_MISC_H
#include "common/defs.h"
/* FST module control interface API */
#define FST_INVALID_SESSION_ID ((u32)-1)
#define FST_MAX_GROUP_ID_SIZE 32
#define FST_MAX_INTERFACE_SIZE 32
enum fst_session_state {
FST_SESSION_STATE_INITIAL,
FST_SESSION_STATE_SETUP_COMPLETION,
FST_SESSION_STATE_TRANSITION_DONE,
FST_SESSION_STATE_TRANSITION_CONFIRMED,
FST_SESSION_STATE_LAST
};
enum fst_event_type {
EVENT_FST_IFACE_STATE_CHANGED, /* An interface has been either attached
* to or detached from an FST group */
EVENT_FST_ESTABLISHED, /* FST Session has been established */
EVENT_FST_SETUP, /* FST Session request received */
EVENT_FST_SESSION_STATE_CHANGED,/* FST Session state has been changed */
EVENT_PEER_STATE_CHANGED, /* FST related generic event occurred,
* see struct fst_hostap_event_data for
* more info */
/* FST Manager internal events */
EVENT_FST_SCAN_STARTED = 100,
EVENT_FST_SCAN_COMPLETED,
EVENT_FST_SIGNAL_CHANGE,
};
enum fst_reason {
REASON_TEARDOWN,
REASON_SETUP,
REASON_SWITCH,
REASON_STT,
REASON_REJECT,
REASON_ERROR_PARAMS,
REASON_RESET,
REASON_DETACH_IFACE,
};
enum fst_initiator {
FST_INITIATOR_UNDEFINED,
FST_INITIATOR_LOCAL,
FST_INITIATOR_REMOTE,
};
union fst_event_extra {
struct fst_event_extra_iface_state {
Boolean attached;
char ifname[FST_MAX_INTERFACE_SIZE];
char group_id[FST_MAX_GROUP_ID_SIZE];
} iface_state; /* for EVENT_FST_IFACE_STATE_CHANGED */
struct fst_event_extra_peer_state {
Boolean connected;
char ifname[FST_MAX_INTERFACE_SIZE];
u8 addr[ETH_ALEN];
} peer_state; /* for EVENT_PEER_STATE_CHANGED */
struct fst_event_extra_session_state {
enum fst_session_state old_state;
enum fst_session_state new_state;
union fst_session_state_switch_extra {
struct {
enum fst_reason reason;
u8 reject_code; /* REASON_REJECT */
/* REASON_SWITCH,
* REASON_TEARDOWN,
* REASON_REJECT
*/
enum fst_initiator initiator;
} to_initial;
} extra;
} session_state; /* for EVENT_FST_SESSION_STATE_CHANGED */
};
/* helpers - prints enum in string form */
#define FST_NAME_UNKNOWN "UNKNOWN"
const char *_fst_get_str_name(unsigned index, const char *names[],
size_t names_size);
int _fst_get_str_num(const char *name, const char *names[],
size_t names_size);
const char *fst_session_event_type_name(enum fst_event_type);
const char *fst_reason_name(enum fst_reason reason);
const char *fst_session_state_name(enum fst_session_state state);
int fst_session_event_num(const char *name);
int fst_reason_num(const char *name);
int fst_session_state_num(const char *name);
#endif /* FST_MISC_H */

View File

@@ -0,0 +1,229 @@
/*
* FST module - shared Control interface definitions
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef FST_CTRL_DEFS_H
#define FST_CTRL_DEFS_H
/* Undefined value */
#define FST_CTRL_PVAL_NONE "NONE"
/* FST-ATTACH parameters */
#define FST_ATTACH_CMD_PNAME_LLT "llt" /* pval = desired LLT */
#define FST_ATTACH_CMD_PNAME_PRIORITY "priority" /* pval = desired priority */
/* FST-MANAGER parameters */
/* FST Session states */
#define FST_CS_PVAL_STATE_INITIAL "INITIAL"
#define FST_CS_PVAL_STATE_SETUP_COMPLETION "SETUP_COMPLETION"
#define FST_CS_PVAL_STATE_TRANSITION_DONE "TRANSITION_DONE"
#define FST_CS_PVAL_STATE_TRANSITION_CONFIRMED "TRANSITION_CONFIRMED"
/* FST Session reset reasons */
#define FST_CS_PVAL_REASON_TEARDOWN "REASON_TEARDOWN"
#define FST_CS_PVAL_REASON_SETUP "REASON_SETUP"
#define FST_CS_PVAL_REASON_SWITCH "REASON_SWITCH"
#define FST_CS_PVAL_REASON_STT "REASON_STT"
#define FST_CS_PVAL_REASON_REJECT "REASON_REJECT"
#define FST_CS_PVAL_REASON_ERROR_PARAMS "REASON_ERROR_PARAMS"
#define FST_CS_PVAL_REASON_RESET "REASON_RESET"
#define FST_CS_PVAL_REASON_DETACH_IFACE "REASON_DETACH_IFACE"
/* FST Session responses */
#define FST_CS_PVAL_RESPONSE_ACCEPT "ACCEPT"
#define FST_CS_PVAL_RESPONSE_REJECT "REJECT"
/* FST Session action initiator */
#define FST_CS_PVAL_INITIATOR_LOCAL "LOCAL"
#define FST_CS_PVAL_INITIATOR_REMOTE "REMOTE"
/* FST-CLI subcommands and parameter names */
#define FST_CMD_HELP "help"
#define FST_CMD_LIST_GROUPS "list_groups"
#define FST_CMD_LIST_IFACES "list_ifaces"
#define FST_CMD_IFACE_PEERS "iface_peers"
#define FST_CMD_GET_PEER_MBIES "get_peer_mbies"
#define FST_CMD_LIST_SESSIONS "list_sessions"
#define FST_CMD_SESSION_ADD "session_add"
#define FST_CMD_SESSION_REMOVE "session_remove"
#define FST_CMD_SESSION_GET "session_get"
#define FST_CSG_PNAME_OLD_PEER_ADDR "old_peer_addr" /* pval = address string */
#define FST_CSG_PNAME_NEW_PEER_ADDR "new_peer_addr" /* pval = address string */
#define FST_CSG_PNAME_OLD_IFNAME "old_ifname" /* pval = ifname */
#define FST_CSG_PNAME_NEW_IFNAME "new_ifname" /* pval = ifname */
#define FST_CSG_PNAME_LLT "llt" /* pval = numeric llt value */
#define FST_CSG_PNAME_STATE "state" /* pval = FST_CS_PVAL_STATE_... */
#define FST_CMD_SESSION_SET "session_set"
#define FST_CSS_PNAME_OLD_PEER_ADDR FST_CSG_PNAME_OLD_PEER_ADDR
#define FST_CSS_PNAME_NEW_PEER_ADDR FST_CSG_PNAME_NEW_PEER_ADDR
#define FST_CSS_PNAME_OLD_IFNAME FST_CSG_PNAME_OLD_IFNAME
#define FST_CSS_PNAME_NEW_IFNAME FST_CSG_PNAME_NEW_IFNAME
#define FST_CSS_PNAME_LLT FST_CSG_PNAME_LLT
#define FST_CMD_SESSION_INITIATE "session_initiate"
#define FST_CMD_SESSION_RESPOND "session_respond"
#define FST_CMD_SESSION_TRANSFER "session_transfer"
#define FST_CMD_SESSION_TEARDOWN "session_teardown"
#ifdef CONFIG_FST_TEST
#define FST_CTR_PVAL_BAD_NEW_BAND "bad_new_band"
#define FST_CMD_TEST_REQUEST "test_request"
#define FST_CTR_IS_SUPPORTED "is_supported"
#define FST_CTR_SEND_SETUP_REQUEST "send_setup_request"
#define FST_CTR_SEND_SETUP_RESPONSE "send_setup_response"
#define FST_CTR_SEND_ACK_REQUEST "send_ack_request"
#define FST_CTR_SEND_ACK_RESPONSE "send_ack_response"
#define FST_CTR_SEND_TEAR_DOWN "send_tear_down"
#define FST_CTR_GET_FSTS_ID "get_fsts_id"
#define FST_CTR_GET_LOCAL_MBIES "get_local_mbies"
#endif
/* Events */
#define FST_CTRL_EVENT_IFACE "FST-EVENT-IFACE"
#define FST_CEI_PNAME_IFNAME "ifname"
#define FST_CEI_PNAME_GROUP "group"
#define FST_CEI_PNAME_ATTACHED "attached"
#define FST_CEI_PNAME_DETACHED "detached"
#define FST_CTRL_EVENT_PEER "FST-EVENT-PEER"
#define FST_CEP_PNAME_IFNAME "ifname"
#define FST_CEP_PNAME_ADDR "peer_addr"
#define FST_CEP_PNAME_CONNECTED "connected"
#define FST_CEP_PNAME_DISCONNECTED "disconnected"
#define FST_CTRL_EVENT_SESSION "FST-EVENT-SESSION"
#define FST_CES_PNAME_SESSION_ID "session_id"
#define FST_CES_PNAME_EVT_TYPE "event_type"
#define FST_PVAL_EVT_TYPE_SESSION_STATE "EVENT_FST_SESSION_STATE"
/* old_state/new_state: pval = FST_CS_PVAL_STATE_... */
#define FST_CES_PNAME_OLD_STATE "old_state"
#define FST_CES_PNAME_NEW_STATE "new_state"
#define FST_CES_PNAME_REASON "reason" /* pval = FST_CS_PVAL_REASON_... */
#define FST_CES_PNAME_REJECT_CODE "reject_code" /* pval = u8 code */
#define FST_CES_PNAME_INITIATOR "initiator" /* pval = FST_CS_PVAL_INITIATOR_... */
#define FST_PVAL_EVT_TYPE_ESTABLISHED "EVENT_FST_ESTABLISHED"
#define FST_PVAL_EVT_TYPE_SETUP "EVENT_FST_SETUP"
#ifdef CONFIG_DBUS
#define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1"
#define WPAS_DBUS_NEW_PATH "/fi/w1/wpa_supplicant1"
#define WPAS_DBUS_NEW_INTERFACE "fi.w1.wpa_supplicant1"
#define WPAS_DBUS_NEW_PATH_INTERFACES WPAS_DBUS_NEW_PATH "/Interfaces"
#define WPAS_DBUS_NEW_IFACE_INTERFACE WPAS_DBUS_NEW_INTERFACE ".Interface"
#define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS"
#define WPAS_DBUS_NEW_PATH_FST WPAS_DBUS_NEW_PATH "/FST"
#define WPAS_DBUS_NEW_IFACE_FST WPAS_DBUS_NEW_INTERFACE ".FST"
#define WPAS_DBUS_NEW_FST_GROUPS_PART "Groups"
#define WPAS_DBUS_NEW_IFACE_FST_GROUP WPAS_DBUS_NEW_IFACE_FST ".Group"
#define WPAS_DBUS_NEW_FST_INTERFACES_PART "Interfaces"
#define WPAS_DBUS_NEW_IFACE_FST_INTERFACE WPAS_DBUS_NEW_IFACE_FST ".Interface"
#define WPAS_DBUS_NEW_FST_SESSIONS_PART "Sessions"
#define WPAS_DBUS_NEW_IFACE_FST_SESSION WPAS_DBUS_NEW_IFACE_FST ".Session"
/*
* Global FST properties, methods and signals
*/
#define FST_DBUS_GLOBAL_PROP_GROUPS "Groups"
#define FST_DBUS_GLOBAL_PROP_SESSIONS "Sessions"
/* Session state change to INITIAL specific fields */
#define FST_DBUS_SIG_SSTATE_PNAME_INIT_REASON "init_reason"
#define FST_DBUS_SIG_SSTATE_PNAME_INIT_REJECT_CODE "reject_code"
#define FST_DBUS_SIG_SSTATE_PNAME_INIT_INITIATOR "initiator"
#define FST_DBUS_GLOBAL_SIG "Global"
#define FST_DBUS_GLOBAL_SIG_PARAM_PATH "path"
#define FST_DBUS_GLOBAL_SIG_PARAM_EVENT "event"
#define FST_DBUS_GLOBAL_SIG_PARAM_PARAMS "params"
#define FST_DBUS_GLOBAL_SIG_SALL_PNAME_SESSION_ID "session_id"
#define FST_DBUS_GLOBAL_SIG_EVT_SESSION_SETUP "SessionSetup"
#define FST_DBUS_GLOBAL_SIG_EVT_SESSION_STATE "SessionState"
#define FST_DBUS_GLOBAL_SIG_SSTATE_PNAME_OLD_STATE "old_state"
#define FST_DBUS_GLOBAL_SIG_SSTATE_PNAME_NEW_STATE "new_state"
#define FST_DBUS_GLOBAL_SIG_SSTATE_PNAME_INIT_REASON \
FST_DBUS_SIG_SSTATE_PNAME_INIT_REASON
#define FST_DBUS_GLOBAL_SIG_SSTATE_PNAME_INIT_REJECT_CODE \
FST_DBUS_SIG_SSTATE_PNAME_INIT_REJECT_CODE
#define FST_DBUS_GLOBAL_SIG_SSTATE_PNAME_INIT_INITIATOR \
FST_DBUS_SIG_SSTATE_PNAME_INIT_INITIATOR
#define FST_DBUS_GLOBAL_SIG_EVT_SESSION_ESTAB "SessionEstablished"
#define FST_DBUS_GLOBAL_SIG_EVT_IFACE_PEER_STATE "InterfacePeerState"
#define FST_DBUS_GLOBAL_SIG_PNAME_IFNAME "path"
#define FST_DBUS_GLOBAL_SIG_PNAME_CONNECTED "connected"
#define FST_DBUS_GLOBAL_SIG_PNAME_PEER_ADDR "peer_addr"
/*
* Group FST properties, methods and signals
*/
#define FST_DBUS_GROUP_PROP_SESSIONS "Sessions"
#define FST_DBUS_GROUP_PROP_IFACES "Interfaces"
#define FST_DBUS_GROUP_MTHD_ADD_SESSION "AddSession"
#define FST_DBUS_GROUP_MTHD_ADD_SESSION_ID_PARAM "session_id"
#define FST_DBUS_GROUP_SIG_SESSION_SETUP "Setup"
#define FST_DBUS_GROUP_SIG_SSESSION_PARAM_PATH "path"
/*
* Session FST properties, methods and signals
*/
#define FST_DBUS_SESSION_SIG_STATE "State"
#define FST_DBUS_SESSION_SIG_PARAM_OLD_STATE "old_state"
#define FST_DBUS_SESSION_SIG_PARAM_NEW_STATE "new_state"
#define FST_DBUS_SESSION_SIG_PARAM_PARAMS "params"
#define FST_DBUS_SESSION_SIG_PNAME_REASON \
FST_DBUS_SIG_SSTATE_PNAME_INIT_REASON
#define FST_DBUS_SESSION_SIG_PNAME_REJECT_CODE \
FST_DBUS_SIG_SSTATE_PNAME_INIT_REJECT_CODE
#define FST_DBUS_SESSION_SIG_PNAME_INITIATOR \
FST_DBUS_SIG_SSTATE_PNAME_INIT_INITIATOR
#define FST_DBUS_SESSION_SIG_ESTABLISHED "Established"
#define FST_DBUS_SESSION_MTHD_SET "Set"
#define FST_DBUS_SESSION_MTHD_SET_PNAME_PNAME "pname"
#define FST_DBUS_SESSION_MTHD_SET_PNAME_PVAL "pvalue"
#define FST_DBUS_SESSION_MTHD_INITIATE "Initiate"
#define FST_DBUS_SESSION_MTHD_RESPOND "Respond"
#define FST_DBUS_SESSION_MTHD_RESPOND_PNAME_STATUS "respond_status"
#define FST_DBUS_SESSION_MTHD_TRANSFER "Transfer"
#define FST_DBUS_SESSION_MTHD_TEARDOWN "TearDown"
#define FST_DBUS_SESSION_MTHD_REMOVE "Remove"
#define FST_DBUS_SESSION_PROP_GROUP "Group"
#define FST_DBUS_SESSION_PROP_ID "ID"
#define FST_DBUS_SESSION_PROP_STATE "State"
#define FST_DBUS_SESSION_PROP_OLD_IFACE "OldInterface"
#define FST_DBUS_SESSION_PROP_NEW_IFACE "NewInterface"
#define FST_DBUS_SESSION_PROP_OWN_ADDR "OwnAddress"
#define FST_DBUS_SESSION_PROP_PEER_ADDR "PeerAddress"
#define FST_DBUS_SESSION_PROP_LLT "LLT"
/*
* Interface FST properties, methods and signals
*/
#define FST_DBUS_IFACE_PROP_GROUP_ID "GroupID"
#define FST_DBUS_IFACE_PROP_PRIORITY "Priority"
#define FST_DBUS_IFACE_PROP_LLT "LLT"
#define FST_DBUS_IFACE_PROP_PEER_ADDR "PeerAddress"
#define FST_DBUS_IFACE_PROP_PEER_MBIEs "PeerMBIEs"
#define FST_DBUS_IFACE_SIG_PEER_STATE "PeerState"
#define FST_DBUS_IFACE_SIG_PNAME_CONNECTED "connected"
#define FST_DBUS_IFACE_SIG_PNAME_PEER_ADDR "peer_addr"
#endif
#endif /* FST_CTRL_DEFS_H */

View File

@@ -0,0 +1,92 @@
/*
* FST module implementation
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/defs.h"
#include "fst_ctrl_defs.h"
#include "fst_ctrl_aux.h"
static const char *session_event_names[] = {
[EVENT_FST_ESTABLISHED] = FST_PVAL_EVT_TYPE_ESTABLISHED,
[EVENT_FST_SETUP] = FST_PVAL_EVT_TYPE_SETUP,
[EVENT_FST_SESSION_STATE_CHANGED] = FST_PVAL_EVT_TYPE_SESSION_STATE,
};
static const char *reason_names[] = {
[REASON_TEARDOWN] = FST_CS_PVAL_REASON_TEARDOWN,
[REASON_SETUP] = FST_CS_PVAL_REASON_SETUP,
[REASON_SWITCH] = FST_CS_PVAL_REASON_SWITCH,
[REASON_STT] = FST_CS_PVAL_REASON_STT,
[REASON_REJECT] = FST_CS_PVAL_REASON_REJECT,
[REASON_ERROR_PARAMS] = FST_CS_PVAL_REASON_ERROR_PARAMS,
[REASON_RESET] = FST_CS_PVAL_REASON_RESET,
[REASON_DETACH_IFACE] = FST_CS_PVAL_REASON_DETACH_IFACE,
};
static const char *session_state_names[] = {
[FST_SESSION_STATE_INITIAL] = FST_CS_PVAL_STATE_INITIAL,
[FST_SESSION_STATE_SETUP_COMPLETION] = FST_CS_PVAL_STATE_SETUP_COMPLETION,
[FST_SESSION_STATE_TRANSITION_DONE] = FST_CS_PVAL_STATE_TRANSITION_DONE,
[FST_SESSION_STATE_TRANSITION_CONFIRMED] = FST_CS_PVAL_STATE_TRANSITION_CONFIRMED,
};
/* helpers */
const char *_fst_get_str_name(unsigned index, const char *names[],
size_t names_size)
{
if (index >= names_size || !names[index])
return FST_NAME_UNKNOWN;
return names[index];
}
int _fst_get_str_num(const char *name, const char *names[],
size_t names_size)
{
unsigned i;
for (i = 0; i < names_size; i++)
if (names[i] && !strncmp(name, names[i], strlen(names[i])))
return i;
return -1;
}
const char *fst_session_event_type_name(enum fst_event_type event)
{
return _fst_get_str_name(event, session_event_names,
ARRAY_SIZE(session_event_names));
}
int fst_session_event_num(const char *name)
{
return _fst_get_str_num(name, session_event_names,
ARRAY_SIZE(session_event_names));
}
const char *fst_reason_name(enum fst_reason reason)
{
return _fst_get_str_name(reason, reason_names, ARRAY_SIZE(reason_names));
}
int fst_reason_num(const char *name)
{
return _fst_get_str_num(name, reason_names, ARRAY_SIZE(reason_names));
}
const char *fst_session_state_name(enum fst_session_state state)
{
return _fst_get_str_name(state, session_state_names,
ARRAY_SIZE(session_state_names));
}
int fst_session_state_num(const char *name)
{
return _fst_get_str_num(name, session_state_names,
ARRAY_SIZE(session_state_names));
}

View File

@@ -0,0 +1,27 @@
The "inih" library is distributed under the New BSD license:
Copyright (c) 2009, Ben Hoyt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Ben Hoyt nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY BEN HOYT ''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 BEN HOYT 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.

View File

@@ -0,0 +1,179 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "ini.h"
#include "utils/includes.h"
#include "utils/common.h"
#if !INI_USE_STACK
#include <stdlib.h>
#endif
#define MAX_SECTION 50
#define MAX_NAME 50
/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}
/* Return pointer to first char c or ';' comment in given string, or pointer to
null at end of string if neither found. ';' must be prefixed by a whitespace
character to register as a comment. */
static char* find_char_or_comment(const char* s, char c)
{
int was_whitespace = 0;
while (*s && *s != c && !(was_whitespace && *s == ';')) {
was_whitespace = isspace((unsigned char)(*s));
s++;
}
return (char*)s;
}
/* See documentation in header file. */
int ini_parse_file(FILE* file,
int (*handler)(void*, const char*, const char*,
const char*),
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
#else
char* line;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_MAX_LINE);
if (!line) {
return -2;
}
#endif
/* Scan through file line by line */
while (fgets(line, INI_MAX_LINE, file) != NULL) {
lineno++;
start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));
if (*start == ';' || *start == '#') {
/* Per Python ConfigParser, allow '#' comments at start of line */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
/* Non-black line with leading whitespace, treat as continuation
of previous name's value (as per Python ConfigParser). */
if (!handler(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_char_or_comment(start + 1, ']');
if (*end == ']') {
*end = '\0';
os_strlcpy(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start && *start != ';') {
/* Not a comment, must be a name[=:]value pair */
end = find_char_or_comment(start, '=');
if (*end != '=') {
end = find_char_or_comment(start, ':');
}
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = lskip(end + 1);
end = find_char_or_comment(value, '\0');
if (*end == ';')
*end = '\0';
rstrip(value);
/* Valid name[=:]value pair found, call handler */
os_strlcpy(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
}
#if INI_STOP_ON_FIRST_ERROR
if (error)
break;
#endif
}
#if !INI_USE_STACK
free(line);
#endif
return error;
}
/* See documentation in header file. */
int ini_parse(const char* filename,
int (*handler)(void*, const char*, const char*, const char*),
void* user)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}

View File

@@ -0,0 +1,77 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#ifndef __INI_H__
#define __INI_H__
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's ConfigParser.
For each name=value pair parsed, call handler function with given user
pointer as well as section, name, and value (data only valid for duration
of handler call). Handler should return nonzero on success, zero on error.
Returns 0 on success, line number of first error on parse error (doesn't
stop on first error), -1 on file open error, or -2 on memory allocation
error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
ConfigParser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
/* Nonzero to use stack, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
/* Maximum line length for any line in INI file. */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
#ifdef __cplusplus
}
#endif
#endif /* __INI_H__ */

View File

@@ -0,0 +1,707 @@
/*
* OS specific functions for UNIX/POSIX systems
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <time.h>
#include <sys/wait.h>
#ifdef ANDROID
#include <sys/capability.h>
#include <sys/prctl.h>
#include <cutils/android_filesystem_config.h>
#endif /* ANDROID */
#include "os.h"
#include "common.h"
#ifdef WPA_TRACE
#include "wpa_debug.h"
#include "trace.h"
#include "list.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_get_reltime(struct os_reltime *t)
{
#if defined(CLOCK_BOOTTIME)
static clockid_t clock_id = CLOCK_BOOTTIME;
#elif defined(CLOCK_MONOTONIC)
static clockid_t clock_id = CLOCK_MONOTONIC;
#else
static clockid_t clock_id = CLOCK_REALTIME;
#endif
struct timespec ts;
int res;
while (1) {
res = clock_gettime(clock_id, &ts);
if (res == 0) {
t->sec = ts.tv_sec;
t->usec = ts.tv_nsec / 1000;
return 0;
}
switch (clock_id) {
#ifdef CLOCK_BOOTTIME
case CLOCK_BOOTTIME:
clock_id = CLOCK_MONOTONIC;
break;
#endif
#ifdef CLOCK_MONOTONIC
case CLOCK_MONOTONIC:
clock_id = CLOCK_REALTIME;
break;
#endif
case CLOCK_REALTIME:
return -1;
}
}
}
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_gmtime(os_time_t t, struct os_tm *tm)
{
struct tm *tm2;
time_t t2 = t;
tm2 = gmtime(&t2);
if (tm2 == NULL)
return -1;
tm->sec = tm2->tm_sec;
tm->min = tm2->tm_min;
tm->hour = tm2->tm_hour;
tm->day = tm2->tm_mday;
tm->month = tm2->tm_mon + 1;
tm->year = tm2->tm_year + 1900;
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)
return NULL;
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.
*/
#ifdef ANDROID_SETGROUPS_OVERRIDE
gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
#else /* ANDROID_SETGROUPS_OVERRIDE */
gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
#endif /* ANDROID_SETGROUPS_OVERRIDE */
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
setgroups(ARRAY_SIZE(groups), 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;
}
int os_file_exists(const char *fname)
{
FILE *f = fopen(fname, "rb");
if (f == NULL)
return 0;
fclose(f);
return 1;
}
#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;
}
int os_memcmp_const(const void *a, const void *b, size_t len)
{
const u8 *aa = a;
const u8 *bb = b;
size_t i;
u8 res;
for (res = 0, i = 0; i < len; i++)
res |= aa[i] ^ bb[i];
return res;
}
#ifdef WPA_TRACE
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
char wpa_trace_fail_func[256] = { 0 };
unsigned int wpa_trace_fail_after;
static int testing_fail_alloc(void)
{
const char *func[WPA_TRACE_LEN];
size_t i, res, len;
char *pos, *next;
int match;
if (!wpa_trace_fail_after)
return 0;
res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
i = 0;
if (i < res && os_strcmp(func[i], __func__) == 0)
i++;
if (i < res && os_strcmp(func[i], "os_malloc") == 0)
i++;
if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
i++;
if (i < res && os_strcmp(func[i], "os_calloc") == 0)
i++;
if (i < res && os_strcmp(func[i], "os_realloc") == 0)
i++;
if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
i++;
if (i < res && os_strcmp(func[i], "os_strdup") == 0)
i++;
pos = wpa_trace_fail_func;
match = 0;
while (i < res) {
int allow_skip = 1;
int maybe = 0;
if (*pos == '=') {
allow_skip = 0;
pos++;
} else if (*pos == '?') {
maybe = 1;
pos++;
}
next = os_strchr(pos, ';');
if (next)
len = next - pos;
else
len = os_strlen(pos);
if (os_memcmp(pos, func[i], len) != 0) {
if (maybe && next) {
pos = next + 1;
continue;
}
if (allow_skip) {
i++;
continue;
}
return 0;
}
if (!next) {
match = 1;
break;
}
pos = next + 1;
i++;
}
if (!match)
return 0;
wpa_trace_fail_after--;
if (wpa_trace_fail_after == 0) {
wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
wpa_trace_fail_func);
for (i = 0; i < res; i++)
wpa_printf(MSG_INFO, "backtrace[%d] = %s",
(int) i, func[i]);
return 1;
}
return 0;
}
#else
static inline int testing_fail_alloc(void)
{
return 0;
}
#endif
void * os_malloc(size_t size)
{
struct os_alloc_trace *a;
if (testing_fail_alloc())
return NULL;
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 */
int os_exec(const char *program, const char *arg, int wait_completion)
{
pid_t pid;
int pid_status;
pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
/* run the external command in the child process */
const int MAX_ARG = 30;
char *_program, *_arg, *pos;
char *argv[MAX_ARG + 1];
int i;
_program = os_strdup(program);
_arg = os_strdup(arg);
argv[0] = _program;
i = 1;
pos = _arg;
while (i < MAX_ARG && pos && *pos) {
while (*pos == ' ')
pos++;
if (*pos == '\0')
break;
argv[i++] = pos;
pos = os_strchr(pos, ' ');
if (pos)
*pos++ = '\0';
}
argv[i] = NULL;
execv(program, argv);
perror("execv");
os_free(_program);
os_free(_arg);
exit(0);
return -1;
}
if (wait_completion) {
/* wait for the child process to complete in the parent */
waitpid(pid, &pid_status, 0);
}
return 0;
}

View File

@@ -0,0 +1,579 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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 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 */
#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 host_to_le32(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 host_to_le32(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 */
static inline u16 WPA_GET_BE16(const u8 *a)
{
return (a[0] << 8) | a[1];
}
static inline void WPA_PUT_BE16(u8 *a, u16 val)
{
a[0] = val >> 8;
a[1] = val & 0xff;
}
static inline u16 WPA_GET_LE16(const u8 *a)
{
return (a[1] << 8) | a[0];
}
static inline void WPA_PUT_LE16(u8 *a, u16 val)
{
a[1] = val >> 8;
a[0] = val & 0xff;
}
static inline u32 WPA_GET_BE24(const u8 *a)
{
return (a[0] << 16) | (a[1] << 8) | a[2];
}
static inline void WPA_PUT_BE24(u8 *a, u32 val)
{
a[0] = (val >> 16) & 0xff;
a[1] = (val >> 8) & 0xff;
a[2] = val & 0xff;
}
static inline u32 WPA_GET_BE32(const u8 *a)
{
return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
}
static inline void WPA_PUT_BE32(u8 *a, u32 val)
{
a[0] = (val >> 24) & 0xff;
a[1] = (val >> 16) & 0xff;
a[2] = (val >> 8) & 0xff;
a[3] = val & 0xff;
}
static inline u32 WPA_GET_LE32(const u8 *a)
{
return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
}
static inline void WPA_PUT_LE32(u8 *a, u32 val)
{
a[3] = (val >> 24) & 0xff;
a[2] = (val >> 16) & 0xff;
a[1] = (val >> 8) & 0xff;
a[0] = val & 0xff;
}
static inline u64 WPA_GET_BE64(const u8 *a)
{
return (((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]);
}
static inline void WPA_PUT_BE64(u8 *a, u64 val)
{
a[0] = val >> 56;
a[1] = val >> 48;
a[2] = val >> 40;
a[3] = val >> 32;
a[4] = val >> 24;
a[5] = val >> 16;
a[6] = val >> 8;
a[7] = val & 0xff;
}
static inline u64 WPA_GET_LE64(const u8 *a)
{
return (((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]);
}
static inline void WPA_PUT_LE64(u8 *a, u64 val)
{
a[7] = val >> 56;
a[6] = val >> 48;
a[5] = val >> 40;
a[4] = val >> 32;
a[3] = val >> 24;
a[2] = val >> 16;
a[1] = val >> 8;
a[0] = val & 0xff;
}
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#ifndef ETH_HLEN
#define ETH_HLEN 14
#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
#ifndef __bitwise
#define __bitwise
#endif
#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 */
#ifndef __maybe_unused
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define __maybe_unused __attribute__((unused))
#else
#define __maybe_unused
#endif /* __GNUC__ */
#endif /* __must_check */
int hwaddr_aton(const char *txt, u8 *addr);
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
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_scnprintf(char *buf, size_t size, const char *fmt, ...);
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);
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
#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 */
void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
char * dup_binstr(const void *src, size_t 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;
}
static inline int is_multicast_ether_addr(const u8 *a)
{
return a[0] & 0x01;
}
#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
#include "wpa_debug.h"
struct wpa_freq_range_list {
struct wpa_freq_range {
unsigned int min;
unsigned int max;
} *range;
unsigned int num;
};
int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
int int_array_len(const int *a);
void int_array_concat(int **res, const int *a);
void int_array_sort_unique(int *a);
void int_array_add_unique(int **res, int a);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
void str_clear_free(char *str);
void bin_clear_free(void *bin, size_t len);
int random_mac_addr(u8 *addr);
int random_mac_addr_keep_oui(u8 *addr);
char * str_token(char *str, const char *delim, char **context);
/*
* 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 */

View File

@@ -0,0 +1,359 @@
/*
* Event loop
* Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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 targeted 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_cancel_timeout_one - Cancel a single timeout
* @handler: Matching callback function
* @eloop_data: Matching eloop_data
* @user_data: Matching user_data
* @remaining: Time left on the cancelled timer
* Returns: Number of cancelled timeouts
*
* Cancel matching <handler,eloop_data,user_data> timeout registered with
* eloop_register_timeout() and return the remaining time left.
*/
int eloop_cancel_timeout_one(eloop_timeout_handler handler,
void *eloop_data, void *user_data,
struct os_reltime *remaining);
/**
* 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_deplete_timeout - Deplete a timeout that is already registered
* @req_secs: Requested number of seconds to the timeout
* @req_usecs: Requested number of microseconds to the timeout
* @handler: Matching callback function
* @eloop_data: Matching eloop_data
* @user_data: Matching user_data
* Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no
* timeout matched
*
* Find a registered matching <handler,eloop_data,user_data> timeout. If found,
* deplete the timeout if remaining time is more than the requested time.
*/
int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
eloop_timeout_handler handler, void *eloop_data,
void *user_data);
/**
* eloop_replenish_timeout - Replenish a timeout that is already registered
* @req_secs: Requested number of seconds to the timeout
* @req_usecs: Requested number of microseconds to the timeout
* @handler: Matching callback function
* @eloop_data: Matching eloop_data
* @user_data: Matching user_data
* Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no
* timeout matched
*
* Find a registered matching <handler,eloop_data,user_data> timeout. If found,
* replenish the timeout if remaining time is less than the requested time.
*/
int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
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 */

View File

@@ -0,0 +1,50 @@
/*
* wpa_supplicant/hostapd - Default include files
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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>
#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
#include <sys/uio.h>
#include <sys/time.h>
#endif /* __vxworks */
#endif /* CONFIG_TI_COMPILER */
#endif /* CONFIG_NATIVE_WINDOWS */
#endif /* INCLUDES_H */

View File

@@ -0,0 +1,95 @@
/*
* Doubly-linked list
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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))
#define DEFINE_DL_LIST(name) \
struct dl_list name = { &(name), &(name) }
#endif /* LIST_H */

View File

@@ -0,0 +1,676 @@
/*
* OS specific functions
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef OS_H
#define OS_H
#ifdef __cplusplus
extern "C" {
#endif
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;
};
struct os_reltime {
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);
/**
* os_get_reltime - Get relative time (sec, usec)
* @t: Pointer to buffer for the time
* Returns: 0 on success, -1 on failure
*/
int os_get_reltime(struct os_reltime *t);
/* Helpers for handling struct os_time */
static inline int os_time_before(struct os_time *a, struct os_time *b)
{
return (a->sec < b->sec) ||
(a->sec == b->sec && a->usec < b->usec);
}
static inline void os_time_sub(struct os_time *a, struct os_time *b,
struct os_time *res)
{
res->sec = a->sec - b->sec;
res->usec = a->usec - b->usec;
if (res->usec < 0) {
res->sec--;
res->usec += 1000000;
}
}
/* Helpers for handling struct os_reltime */
static inline int os_reltime_before(struct os_reltime *a,
struct os_reltime *b)
{
return (a->sec < b->sec) ||
(a->sec == b->sec && a->usec < b->usec);
}
static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
struct os_reltime *res)
{
res->sec = a->sec - b->sec;
res->usec = a->usec - b->usec;
if (res->usec < 0) {
res->sec--;
res->usec += 1000000;
}
}
static inline void os_reltime_age(struct os_reltime *start,
struct os_reltime *age)
{
struct os_reltime now;
os_get_reltime(&now);
os_reltime_sub(&now, start, age);
}
static inline int os_reltime_expired(struct os_reltime *now,
struct os_reltime *ts,
os_time_t timeout_secs)
{
struct os_reltime age;
os_reltime_sub(now, ts, &age);
return (age.sec > timeout_secs) ||
(age.sec == timeout_secs && age.usec > 0);
}
static inline int os_reltime_initialized(struct os_reltime *t)
{
return t->sec != 0 || t->usec != 0;
}
static inline size_t memscpy(void* dst, size_t dst_size,
const void* src, size_t src_size)
{
size_t copy_size = (dst_size <= src_size)? dst_size : src_size;
memcpy(dst, src, copy_size);
return copy_size;
}
static inline size_t memsmove(void *dst, size_t dst_size,
const void *src, size_t src_size)
{
size_t copy_size = (dst_size <= src_size)? dst_size : src_size;
memmove(dst, src, copy_size);
return copy_size;
}
/**
* 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);
struct os_tm {
int sec; /* 0..59 or 60 for leap seconds */
int min; /* 0..59 */
int hour; /* 0..23 */
int day; /* 1..31 */
int month; /* 1..12 */
int year; /* Four digit year */
};
int os_gmtime(os_time_t t, struct os_tm *tm);
/**
* 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_file_exists - Check whether the specified file exists
* @fname: Path and name of the file
* Returns: 1 if the file exists or 0 if not
*/
int os_file_exists(const char *fname);
/**
* 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);
/**
* os_calloc - Allocate and zero memory for an array
* @nmemb: Number of members in the array
* @size: Number of bytes in each member
* Returns: Pointer to allocated and zeroed memory or %NULL on failure
*
* This function can be used as a wrapper for os_zalloc(nmemb * size) when an
* allocation is used for an array. The main benefit over os_zalloc() is in
* having an extra check to catch integer overflows in multiplication.
*
* Caller is responsible for freeing the returned buffer with os_free().
*/
static inline void * os_calloc(size_t nmemb, size_t size)
{
if (size && nmemb > (~(size_t) 0) / size)
return NULL;
return os_zalloc(nmemb * 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_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) memscpy((d), (n), (s), (n))
#endif
#ifndef os_memmove
#define os_memmove(d, s, n) memsmove((d), (n), (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_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 */
static inline int os_snprintf_error(size_t size, int res)
{
return res < 0 || (unsigned int) res >= size;
}
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
{
if (size && nmemb > (~(size_t) 0) / size)
return NULL;
return os_realloc(ptr, nmemb * size);
}
/**
* os_remove_in_array - Remove a member from an array by index
* @ptr: Pointer to the array
* @nmemb: Current member count of the array
* @size: The size per member of the array
* @idx: Index of the member to be removed
*/
static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size,
size_t idx)
{
if (idx < nmemb - 1)
os_memmove(((unsigned char *) ptr) + idx * size,
((unsigned char *) ptr) + (idx + 1) * size,
(nmemb - idx - 1) * size);
}
/**
* 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);
/**
* os_memcmp_const - Constant time memory comparison
* @a: First buffer to compare
* @b: Second buffer to compare
* @len: Number of octets to compare
* Returns: 0 if buffers are equal, non-zero if not
*
* This function is meant for comparing passwords or hash values where
* difference in execution time could provide external observer information
* about the location of the difference in the memory buffers. The return value
* does not behave like os_memcmp(), i.e., os_memcmp_const() cannot be used to
* sort items into a defined order. Unlike os_memcmp(), execution time of
* os_memcmp_const() does not depend on the contents of the compared memory
* buffers, but only on the total compared length.
*/
int os_memcmp_const(const void *a, const void *b, size_t len);
/**
* os_exec - Execute an external program
* @program: Path to the program
* @arg: Command line argument string
* @wait_completion: Whether to wait until the program execution completes
* Returns: 0 on success, -1 on error
*/
int os_exec(const char *program, const char *arg, int wait_completion);
#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 */
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OS_H */

View File

@@ -0,0 +1,69 @@
/*
* Backtrace debugging
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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);
size_t wpa_trace_calling_func(const char *buf[], size_t len);
#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 */

View File

@@ -0,0 +1,375 @@
/*
* wpa_supplicant/hostapd / Debug prints
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_DEBUG_H
#define WPA_DEBUG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "wpabuf.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
/* 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_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_debug_setup_stdout() 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);
void wpa_debug_setup_stdout(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 void *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 void *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) : NULL,
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 void *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 void *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 */
#ifdef CONFIG_NO_WPA_MSG
#define wpa_msg(args...) do { } while (0)
#define wpa_msg_ctrl(args...) do { } while (0)
#define wpa_msg_global(args...) do { } while (0)
#define wpa_msg_global_ctrl(args...) do { } while (0)
#define wpa_msg_no_global(args...) do { } while (0)
#define wpa_msg_global_only(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);
/**
* wpa_msg_global - Global 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 as a global event,
* i.e., without being specific to an interface. For backwards compatibility,
* an old style event is also delivered on one of the interfaces (the one
* specified by the context data).
*/
void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
/**
* wpa_msg_global_ctrl - Conditional global 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_global(), but it sends the output only to the
* attached global 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_global_ctrl(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
/**
* wpa_msg_no_global - 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 does not send the output as a global
* event.
*/
void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
/**
* wpa_msg_global_only - 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_global(), but it sends the output only as a
* global event.
*/
void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
enum wpa_msg_type {
WPA_MSG_PER_INTERFACE,
WPA_MSG_GLOBAL,
WPA_MSG_NO_GLOBAL,
WPA_MSG_ONLY_GLOBAL,
};
typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type,
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 CONFIG_DEBUG_LINUX_TRACING
int wpa_debug_open_linux_tracing(void);
void wpa_debug_close_linux_tracing(void);
#else /* CONFIG_DEBUG_LINUX_TRACING */
static inline int wpa_debug_open_linux_tracing(void)
{
return 0;
}
static inline void wpa_debug_close_linux_tracing(void)
{
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
#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
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* WPA_DEBUG_H */

View File

@@ -0,0 +1,163 @@
/*
* Dynamic data buffer
* Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPABUF_H
#define WPABUF_H
/* wpabuf::buf is a pointer to external data */
#define WPABUF_FLAG_EXT_DATA BIT(0)
/*
* 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 *buf; /* pointer to the head of the buffer */
unsigned int flags;
/* 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_clear_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)
{
return buf->buf;
}
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
{
return (const u8 *)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)
{
return buf->buf;
}
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
{
return (u8 *)wpabuf_mhead(buf);
}
static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
{
u8 *pos = (u8 *)wpabuf_put(buf, 1);
*pos = data;
}
static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
{
u8 *pos = (u8 *)wpabuf_put(buf, 2);
WPA_PUT_LE16(pos, data);
}
static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
{
u8 *pos = (u8 *)wpabuf_put(buf, 4);
WPA_PUT_LE32(pos, data);
}
static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
{
u8 *pos = (u8 *)wpabuf_put(buf, 2);
WPA_PUT_BE16(pos, data);
}
static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
{
u8 *pos = (u8 *)wpabuf_put(buf, 3);
WPA_PUT_BE24(pos, data);
}
static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
{
u8 *pos = (u8 *)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->buf = (u8 *) data;
buf->flags = WPABUF_FLAG_EXT_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 */

View File

@@ -0,0 +1,733 @@
/*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
#include <netdb.h>
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#ifdef ANDROID
#include <dirent.h>
#include <sys/stat.h>
#include <cutils/sockets.h>
#include "cutils/android_filesystem_config.h"
#endif /* ANDROID */
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
#include <net/if.h>
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#include "wpa_ctrl.h"
#include "common.h"
#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
#define CTRL_IFACE_SOCKET
#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
/**
* struct wpa_ctrl - Internal structure for control interface library
*
* This structure is used by the wpa_supplicant/hostapd control interface
* library to store internal data. Programs using the library should not touch
* this data directly. They can only use the pointer to the data structure as
* an identifier for the control interface connection and use this as one of
* the arguments for most of the control interface library functions.
*/
struct wpa_ctrl {
#ifdef CONFIG_CTRL_IFACE_UDP
int s;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 local;
struct sockaddr_in6 dest;
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in local;
struct sockaddr_in dest;
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
char *cookie;
char *remote_ifname;
char *remote_ip;
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_CTRL_IFACE_UNIX
int s;
struct sockaddr_un local;
struct sockaddr_un dest;
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
HANDLE pipe;
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
};
#ifdef CONFIG_CTRL_IFACE_UNIX
#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
int flags;
if (ctrl_path == NULL)
return NULL;
ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
if (socket_local_client_connect(
ctrl->s, ctrl_path + 9,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_DGRAM) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
/*
* If the ctrl_path isn't an absolute pathname, assume that
* it's the name of a socket in the Android reserved namespace.
* Otherwise, it's a normal UNIX domain socket appearing in the
* filesystem.
*/
if (*ctrl_path != '/') {
char buf[21];
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
if (socket_local_client_connect(
ctrl->s, buf,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_DGRAM) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
#endif /* ANDROID */
ctrl->dest.sun_family = AF_UNIX;
if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
ctrl->dest.sun_path[0] = '\0';
os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
sizeof(ctrl->dest.sun_path) - 1);
} else {
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
/*
* Make socket non-blocking so that we don't hang forever if
* target dies unexpectedly.
*/
flags = fcntl(ctrl->s, F_GETFL);
if (flags >= 0) {
flags |= O_NONBLOCK;
if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
perror("fcntl(ctrl->s, O_NONBLOCK)");
/* Not fatal, continue on.*/
}
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
if (ctrl == NULL)
return;
unlink(ctrl->local.sun_path);
if (ctrl->s >= 0)
close(ctrl->s);
os_free(ctrl);
}
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
* may be left over from clients that were previously connected to
* wpa_supplicant. This keeps these files from being orphaned in the
* event of crashes that prevented them from being removed as part
* of the normal orderly shutdown.
*/
void wpa_ctrl_cleanup(void)
{
DIR *dir;
struct dirent entry;
struct dirent *result;
size_t dirnamelen;
size_t maxcopy;
char pathname[PATH_MAX];
char *namep;
if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
return;
dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
CONFIG_CTRL_IFACE_CLIENT_DIR);
if (dirnamelen >= sizeof(pathname)) {
closedir(dir);
return;
}
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
unlink(pathname);
}
closedir(dir);
}
#endif /* ANDROID */
#else /* CONFIG_CTRL_IFACE_UNIX */
#ifdef ANDROID
void wpa_ctrl_cleanup(void)
{
}
#endif /* ANDROID */
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_UDP
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
char buf[128];
size_t len;
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
struct hostent *h;
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (ctrl->s < 0) {
perror("socket");
os_free(ctrl);
return NULL;
}
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
ctrl->local.sin6_family = AF_INET6;
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
ctrl->local.sin6_addr = in6addr_any;
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->local.sin_family = AF_INET;
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
ctrl->local.sin_addr.s_addr = INADDR_ANY;
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
ctrl->dest.sin6_family = AF_INET6;
inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
if (ctrl_path) {
char *port, *name;
int port_id;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
char *scope;
int scope_id = 0;
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
name = os_strdup(ctrl_path);
if (name == NULL) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
port = os_strchr(name, ',');
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
port = os_strchr(name, ':');
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (port) {
port_id = atoi(&port[1]);
port[0] = '\0';
} else
port_id = WPA_CTRL_IFACE_PORT;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
scope = os_strchr(name, '%');
if (scope) {
scope_id = if_nametoindex(&scope[1]);
scope[0] = '\0';
}
h = gethostbyname2(name, AF_INET6);
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
h = gethostbyname(name);
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->remote_ip = os_strdup(name);
os_free(name);
if (h == NULL) {
perror("gethostbyname");
close(ctrl->s);
os_free(ctrl->remote_ip);
os_free(ctrl);
return NULL;
}
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
ctrl->dest.sin6_scope_id = scope_id;
ctrl->dest.sin6_port = htons(port_id);
os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->dest.sin_port = htons(port_id);
os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
} else
ctrl->remote_ip = os_strdup("localhost");
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
char addr[INET6_ADDRSTRLEN];
wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
sizeof(ctrl->dest)),
ntohs(ctrl->dest.sin6_port),
strerror(errno));
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
inet_ntoa(ctrl->dest.sin_addr),
ntohs(ctrl->dest.sin_port),
strerror(errno));
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
close(ctrl->s);
os_free(ctrl->remote_ip);
os_free(ctrl);
return NULL;
}
len = sizeof(buf) - 1;
if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
buf[len] = '\0';
ctrl->cookie = os_strdup(buf);
}
if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
buf[len] = '\0';
ctrl->remote_ifname = os_strdup(buf);
}
return ctrl;
}
char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
{
#define WPA_CTRL_MAX_PS_NAME 100
static char ps[WPA_CTRL_MAX_PS_NAME] = {};
os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
ctrl->remote_ip, ctrl->remote_ifname);
return ps;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl->cookie);
os_free(ctrl->remote_ifname);
os_free(ctrl->remote_ip);
os_free(ctrl);
}
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
struct os_reltime started_at;
int res;
fd_set rfds;
const char *_cmd;
char *cmd_buf = NULL;
size_t _cmd_len;
#ifdef CONFIG_CTRL_IFACE_UDP
if (ctrl->cookie) {
char *pos;
_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
cmd_buf = os_malloc(_cmd_len);
if (cmd_buf == NULL)
return -1;
_cmd = cmd_buf;
pos = cmd_buf;
os_strlcpy(pos, ctrl->cookie, _cmd_len);
pos += os_strlen(ctrl->cookie);
*pos++ = ' ';
os_memcpy(pos, cmd, cmd_len);
} else
#endif /* CONFIG_CTRL_IFACE_UDP */
{
_cmd = cmd;
_cmd_len = cmd_len;
}
errno = 0;
started_at.sec = 0;
started_at.usec = 0;
retry_send:
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
{
/*
* Must be a non-blocking socket... Try for a bit
* longer before giving up.
*/
if (started_at.sec == 0)
os_get_reltime(&started_at);
else {
struct os_reltime n;
os_get_reltime(&n);
/* Try for a few seconds. */
if (os_reltime_expired(&n, &started_at, 5))
goto send_err;
}
os_sleep(1, 0);
goto retry_send;
}
send_err:
os_free(cmd_buf);
return -1;
}
os_free(cmd_buf);
for (;;) {
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
if (res < 0)
return res;
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}
#endif /* CTRL_IFACE_SOCKET */
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
{
char buf[10];
int ret;
size_t len = 10;
ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
buf, &len, NULL);
if (ret < 0)
return ret;
if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}
int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 1);
}
int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 0);
}
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
struct timeval tv;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return ctrl->s;
}
#endif /* CTRL_IFACE_SOCKET */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
#ifndef WPA_SUPPLICANT_NAMED_PIPE
#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
#endif
#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
DWORD mode;
TCHAR name[256];
int i, ret;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
#ifdef UNICODE
if (ctrl_path == NULL)
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
ctrl_path);
#else /* UNICODE */
if (ctrl_path == NULL)
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
ctrl_path);
#endif /* UNICODE */
if (os_snprintf_error(256, ret)) {
os_free(ctrl);
return NULL;
}
for (i = 0; i < 10; i++) {
ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
/*
* Current named pipe server side in wpa_supplicant is
* re-opening the pipe for new clients only after the previous
* one is taken into use. This leaves a small window for race
* conditions when two connections are being opened at almost
* the same time. Retry if that was the case.
*/
if (ctrl->pipe != INVALID_HANDLE_VALUE ||
GetLastError() != ERROR_PIPE_BUSY)
break;
WaitNamedPipe(name, 1000);
}
if (ctrl->pipe == INVALID_HANDLE_VALUE) {
os_free(ctrl);
return NULL;
}
mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
CloseHandle(ctrl->pipe);
os_free(ctrl);
return NULL;
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
CloseHandle(ctrl->pipe);
os_free(ctrl);
}
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
DWORD written;
DWORD readlen = *reply_len;
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
return -1;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
return -1;
*reply_len = readlen;
return 0;
}
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
DWORD len = *reply_len;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
return -1;
*reply_len = len;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
DWORD left;
if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
return -1;
return left ? 1 : 0;
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return -1;
}
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
#endif /* CONFIG_CTRL_IFACE */

View File

@@ -0,0 +1,819 @@
/*
* wpa_supplicant/hostapd / Debug prints
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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 */
#ifdef CONFIG_DEBUG_LINUX_TRACING
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
static FILE *wpa_debug_tracing_file = NULL;
#define WPAS_TRACE_PFX "wpas <%d>: "
#endif /* CONFIG_DEBUG_LINUX_TRACING */
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>
#ifndef ANDROID_LOG_NAME
#define ANDROID_LOG_NAME "wpa_supplicant"
#endif /* ANDROID_LOG_NAME */
static int wpa_to_android_level(int level)
{
if (level == MSG_ERROR)
return ANDROID_LOG_ERROR;
if (level == MSG_WARNING)
return ANDROID_LOG_WARN;
if (level == MSG_INFO)
return ANDROID_LOG_INFO;
return ANDROID_LOG_DEBUG;
}
#endif /* 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)
{
#ifndef CONFIG_ANDROID_LOG
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);
#endif /* CONFIG_ANDROID_LOG */
}
#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 */
#ifdef CONFIG_DEBUG_LINUX_TRACING
int wpa_debug_open_linux_tracing(void)
{
int mounts, trace_fd;
char buf[4096] = {};
ssize_t buflen;
char *line, *tmp1, *path = NULL;
mounts = open("/proc/mounts", O_RDONLY);
if (mounts < 0) {
printf("no /proc/mounts\n");
return -1;
}
buflen = read(mounts, buf, sizeof(buf) - 1);
close(mounts);
if (buflen < 0) {
printf("failed to read /proc/mounts\n");
return -1;
}
line = strtok_r(buf, "\n", &tmp1);
while (line) {
char *tmp2, *tmp_path, *fstype;
/* "<dev> <mountpoint> <fs type> ..." */
strtok_r(line, " ", &tmp2);
tmp_path = strtok_r(NULL, " ", &tmp2);
fstype = strtok_r(NULL, " ", &tmp2);
if (strcmp(fstype, "debugfs") == 0) {
path = tmp_path;
break;
}
line = strtok_r(NULL, "\n", &tmp1);
}
if (path == NULL) {
printf("debugfs mountpoint not found\n");
return -1;
}
snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
trace_fd = open(buf, O_WRONLY);
if (trace_fd < 0) {
printf("failed to open trace_marker file\n");
return -1;
}
wpa_debug_tracing_file = fdopen(trace_fd, "w");
if (wpa_debug_tracing_file == NULL) {
close(trace_fd);
printf("failed to fdopen()\n");
return -1;
}
return 0;
}
void wpa_debug_close_linux_tracing(void)
{
if (wpa_debug_tracing_file == NULL)
return;
fclose(wpa_debug_tracing_file);
wpa_debug_tracing_file = NULL;
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
/**
* 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_ANDROID_LOG
__android_log_vprint(wpa_to_android_level(level),
ANDROID_LOG_NAME, fmt, ap);
#else /* CONFIG_ANDROID_LOG */
#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 */
#endif /* CONFIG_ANDROID_LOG */
}
va_end(ap);
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
va_start(ap, fmt);
fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
vfprintf(wpa_debug_tracing_file, fmt, ap);
fprintf(wpa_debug_tracing_file, "\n");
fflush(wpa_debug_tracing_file);
va_end(ap);
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
}
static void _wpa_hexdump(int level, const char *title, const u8 *buf,
size_t len, int show)
{
size_t i;
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
fprintf(wpa_debug_tracing_file,
WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
level, title, (unsigned long) len);
if (buf == NULL) {
fprintf(wpa_debug_tracing_file, " [NULL]\n");
} else if (!show) {
fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
} else {
for (i = 0; i < len; i++)
fprintf(wpa_debug_tracing_file,
" %02x", buf[i]);
}
fflush(wpa_debug_tracing_file);
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
if (level < wpa_debug_level)
return;
#ifdef CONFIG_ANDROID_LOG
{
const char *display;
char *strbuf = NULL;
size_t slen = len;
if (buf == NULL) {
display = " [NULL]";
} else if (len == 0) {
display = "";
} else if (show && len) {
/* Limit debug message length for Android log */
if (slen > 32)
slen = 32;
strbuf = os_malloc(1 + 3 * slen);
if (strbuf == NULL) {
wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
"allocate message buffer");
return;
}
for (i = 0; i < slen; i++)
os_snprintf(&strbuf[i * 3], 4, " %02x",
buf[i]);
display = strbuf;
} else {
display = " [REMOVED]";
}
__android_log_print(wpa_to_android_level(level),
ANDROID_LOG_NAME,
"%s - hexdump(len=%lu):%s%s",
title, (long unsigned int) len, display,
len > slen ? " ..." : "");
os_free(strbuf);
return;
}
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
const char *display;
char *strbuf = NULL;
if (buf == NULL) {
display = " [NULL]";
} else if (len == 0) {
display = "";
} else if (show && len) {
strbuf = os_malloc(1 + 3 * len);
if (strbuf == NULL) {
wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
"allocate message buffer");
return;
}
for (i = 0; i < len; i++)
os_snprintf(&strbuf[i * 3], 4, " %02x",
buf[i]);
display = strbuf;
} else {
display = " [REMOVED]";
}
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
title, (unsigned long) len, display);
os_free(strbuf);
return;
}
#endif /* CONFIG_DEBUG_SYSLOG */
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 */
#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
{
_wpa_hexdump(level, title, buf, len, 1);
}
void wpa_hexdump_key(int level, const char *title, const void *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 void *buf,
size_t len, int show)
{
size_t i, llen;
const u8 *pos = buf;
const size_t line_len = 16;
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
fprintf(wpa_debug_tracing_file,
WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
level, title, (unsigned long) len);
if (buf == NULL) {
fprintf(wpa_debug_tracing_file, " [NULL]\n");
} else if (!show) {
fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
} else {
/* can do ascii processing in userspace */
for (i = 0; i < len; i++)
fprintf(wpa_debug_tracing_file,
" %02x", pos[i]);
}
fflush(wpa_debug_tracing_file);
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
if (level < wpa_debug_level)
return;
#ifdef CONFIG_ANDROID_LOG
_wpa_hexdump(level, title, buf, len, show);
#else /* CONFIG_ANDROID_LOG */
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 */
#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump_ascii(int level, const char *title, const void *buf,
size_t len)
{
_wpa_hexdump_ascii(level, title, buf, len, 1);
}
void wpa_hexdump_ascii_key(int level, const char *title, const void *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 */
#else /* CONFIG_DEBUG_FILE */
(void)path;
#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 */
}
void wpa_debug_setup_stdout(void)
{
#ifndef _WIN32
setvbuf(stdout, NULL, _IOLBF, 0);
#endif /* _WIN32 */
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
#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;
int buflen;
int len;
char prefix[130];
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
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 (os_snprintf_error(sizeof(prefix), res))
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, WPA_MSG_PER_INTERFACE, buf, len);
os_free(buf);
}
void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
int buflen;
int len;
if (!wpa_msg_cb)
return;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
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, WPA_MSG_PER_INTERFACE, buf, len);
os_free(buf);
}
void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
int buflen;
int len;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
"message buffer");
return;
}
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
os_free(buf);
}
void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
int buflen;
int len;
if (!wpa_msg_cb)
return;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"wpa_msg_global_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, WPA_MSG_GLOBAL, buf, len);
os_free(buf);
}
void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
int buflen;
int len;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
"message buffer");
return;
}
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
os_free(buf);
}
void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
int buflen;
int len;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
"message buffer");
return;
}
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, 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;
int buflen;
int len;
va_start(ap, fmt);
buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
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 */

View File

@@ -0,0 +1,82 @@
/*
* Provides access to the capablity config store in Android
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <vendor/qti/hardware/capabilityconfigstore/1.0/ICapabilityConfigStore.h>
#include <vendor/qti/hardware/capabilityconfigstore/1.0/types.h>
#define FST_MGR_COMPONENT "CCS"
#include "fst_manager.h"
#include "utils/common.h"
#include "utils/os.h"
#include "fst_capconfigstore.h"
using android::hardware::hidl_string;
using namespace android;
using CommandResult = ::vendor::qti::hardware::capabilityconfigstore::V1_0::CommandResult;
using Result = ::vendor::qti::hardware::capabilityconfigstore::V1_0::Result;
using ICapabilityConfigStore = ::vendor::qti::hardware::capabilityconfigstore::V1_0::ICapabilityConfigStore;
#define WIGIG_CONFIG_STORE_AREA "wigig"
void fst_get_config_string(const char *key, const char *defvalue,
char *buf, size_t len)
{
sp<ICapabilityConfigStore> service;
CommandResult res;
res.result_type = Result::NOT_FOUND;
service = ICapabilityConfigStore::getService();
if (!service) {
fst_mgr_printf(MSG_ERROR,
"failed to get capconfigstore service");
goto out;
}
service->getConfig(WIGIG_CONFIG_STORE_AREA, key, [&](const CommandResult& res) {
if(res.result_type == Result::SUCCESS) {
fst_mgr_printf(MSG_DEBUG,
"getConfig: key %s returned value %s",
key, res.value.c_str());
os_strlcpy(buf, res.value.c_str(), len);
} else {
fst_mgr_printf(MSG_DEBUG,
"getConfig: failed to get key %s",
key);
}
});
out:
if (res.result_type != Result::SUCCESS) {
fst_mgr_printf(MSG_DEBUG, "getConfig: use default value %s", defvalue);
os_strlcpy(buf, defvalue, len);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Provides access to the capablity config store in Android
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_CAPCONFIGSTORE_H__
#define __FST_CAPCONFIGSTORE_H__
#ifdef __cplusplus
extern "C"
{
#endif
void fst_get_config_string(const char *key, const char *defvalue,
char *buf, size_t len);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FST_CAPCONFIGSTORE_H__ */

View File

@@ -0,0 +1,964 @@
/*
* FST Manager: FST Configuration Manager
*
* Copyright (c) 2015-2016,2019-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <linux/sockios.h>
#include "fst_cfgmgr.h"
#include "fst_rateupg.h"
#include "fst_ini_conf.h"
#define FST_MGR_COMPONENT "CFGMGR"
#include "fst_manager.h"
static struct fst_config_ctx
{
enum fst_config_method method;
struct fst_ini_config *handle;
int skfd;
} fstcfg = {FST_CONFIG_CLI, NULL, -1};
static int _get_iface_flags(int sock, const char *ifname, short int *flags)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
fst_mgr_printf(MSG_ERROR, "Error getting interface %s flags", ifname);
return -2;
}
*flags = ifr.ifr_flags;
return 0;
}
static int set_iface_flags(int sock, const char *ifname, short int flags)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
fst_mgr_printf(MSG_ERROR, "Error setting interface %s flags", ifname);
return -2;
}
return 0;
}
static int set_iface_txqueuelen(int sock, const char *ifname, int txqueuelen)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_qlen = txqueuelen;
fst_mgr_printf(MSG_INFO, "Setting %s txqueuelen %d", ifname, txqueuelen);
if (ioctl(sock, SIOCSIFTXQLEN, &ifr) != 0) {
fst_mgr_printf(MSG_ERROR, "Error setting interface %s txqueuelen", ifname);
return -1;
}
return 0;
}
static int _set_iface_up(int sock, const char *ifname, Boolean up)
{
short int flags;
int ret;
if (sock < 0)
return -1;
ret = _get_iface_flags(sock, ifname, &flags);
if (ret < 0)
return ret;
if (up) {
if (flags & IFF_UP)
return 0;
flags |= IFF_UP;
} else {
if (!(flags & IFF_UP))
return 0;
flags &= ~IFF_UP;
}
return set_iface_flags(sock, ifname, flags);
}
int set_iface_up(const char *ifname, Boolean up)
{
return _set_iface_up(fstcfg.skfd, ifname, up);
}
int get_iface_flags(const char *ifname, short int *flags)
{
return _get_iface_flags(fstcfg.skfd, ifname, flags);
}
static int enslave_device(int sock, const char *bond, const char *ifname)
{
struct ifreq if_enslave;
short int iface_flags;
if (sock < 0)
return -1;
if (_get_iface_flags(sock, ifname, &iface_flags) < 0)
return -1;
if (iface_flags & IFF_SLAVE) {
fst_mgr_printf(MSG_INFO, "Interface %s already enslaved", ifname);
return 0;
}
/* Device should be down before bonding in new kernels */
iface_flags &= ~IFF_UP;
if (set_iface_flags(sock, ifname, iface_flags) < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot down slave %s", ifname);
return -2;
}
/* Enslave the device */
os_strlcpy(if_enslave.ifr_name, bond, IFNAMSIZ);
os_strlcpy(if_enslave.ifr_slave, ifname, IFNAMSIZ);
if ((ioctl(sock, SIOCBONDENSLAVE, &if_enslave) < 0)) {
fst_mgr_printf(MSG_ERROR, "Error enslaving %s to %s: %s",
ifname, bond, strerror(errno));
return -2;
}
return 0;
}
static int release_device(int sock, const char *bond, const char *ifname)
{
struct ifreq if_enslave;
short int iface_flags;
if (sock < 0)
return -1;
if (_get_iface_flags(sock, ifname, &iface_flags) < 0)
return -1;
if (!(iface_flags & IFF_SLAVE)) {
fst_mgr_printf(MSG_INFO, "Interface %s not enslaved", ifname);
return 0;
}
/* Release the device */
os_strlcpy(if_enslave.ifr_name, bond, IFNAMSIZ);
os_strlcpy(if_enslave.ifr_slave, ifname, IFNAMSIZ);
if ((ioctl(sock, SIOCBONDRELEASE, &if_enslave) < 0)) {
fst_mgr_printf(MSG_ERROR, "Error releasing %s from %s: %s",
ifname, bond, strerror(errno));
return -2;
}
return 0;
}
static int fst_cfgmgr_get_txqueuelen(const char *gname)
{
int res = -1;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_txqueuelen(fstcfg.handle, gname);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
break;
}
return res;
}
int fst_set_mac_address(struct fst_group_info *ginfo, const u8 *mac)
{
struct ifreq ifr;
int ret;
char bond[80];
if (fst_cfgmgr_get_mux_ifname(ginfo->id, bond, sizeof(bond)-1) <= 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux name for %s", ginfo->id);
return -1;
}
os_strlcpy(ifr.ifr_name, bond, IFNAMSIZ);
memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ALEN);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
ret = ioctl(fstcfg.skfd, SIOCSIFHWADDR, &ifr);
if (ret < 0)
fst_mgr_printf(MSG_ERROR, "SIOCSIFHWADDR failed on %s: %s",
bond, strerror(errno));
return ret;
}
int fst_iface_enslave(struct fst_group_info *ginfo, const char *ifname, Boolean enslave)
{
int res;
char bond[80];
if (fst_cfgmgr_get_mux_ifname(ginfo->id, bond, sizeof(bond)-1) <= 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux name for %s", ginfo->id);
return -1;
}
fst_mgr_printf(MSG_DEBUG,
"%s interface %s to mux %s (group %s)",
enslave ? "Enslaving":"Releasing", ifname,
bond, ginfo->id);
if (enslave)
res = enslave_device(fstcfg.skfd, bond, ifname);
else
res = release_device(fstcfg.skfd, bond, ifname);
if (res < 0)
fst_mgr_printf(MSG_ERROR, "Cannot enslave/release %s", ifname);
return res;
}
int fst_cfgmgr_update_txqueuelen(const struct fst_group_info *group)
{
int sock = fstcfg.skfd, txqueuelen, res = 0;
char buf[80];
if (fst_cfgmgr_get_mux_ifname(group->id, buf, sizeof(buf)-1) <= 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux name for %s",
group->id);
return -1;
}
txqueuelen = fst_cfgmgr_get_txqueuelen(group->id);
if (txqueuelen >= 0)
res = set_iface_txqueuelen(sock, buf, txqueuelen);
return res;
}
int fst_cfgmgr_set_mux_iface_up(const struct fst_group_info *group, Boolean up)
{
int sock = fstcfg.skfd, res;
char buf[80];
if (fst_cfgmgr_get_mux_ifname(group->id, buf, sizeof(buf)-1) <= 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux name for %s",
group->id);
return -1;
}
res = (_set_iface_up(sock, buf, up) < 0);
if (res) {
fst_mgr_printf(MSG_ERROR, "Cannot set iface %s to state %s",
buf, up ? "UP" : "DOWN");
}
return res;
}
static int do_bonding_operations(Boolean enslave)
{
struct fst_group_info *groups;
struct fst_iface_info *ifaces;
int gcnt, icnt, muxtype, sock = fstcfg.skfd, i, j, res;
char buf[80];
Boolean enslaved_any;
if (fstcfg.handle == NULL) {
fst_mgr_printf(MSG_ERROR, "Interfaces configuration not found");
goto error_handle;
}
gcnt = fst_ini_config_get_groups(fstcfg.handle, &groups);
if (gcnt < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot read groups");
goto error_groups;
}
for (i = 0; i < gcnt; i++) {
muxtype = fst_cfgmgr_get_mux_type(groups[i].id,
buf, sizeof(buf)-1);
if (muxtype && os_strncmp(buf, "bonding", sizeof(buf)-1) &&
os_strncmp(buf, "bonding_l2da", sizeof(buf)-1)) {
fst_mgr_printf(MSG_DEBUG,
"Group %s mux type %s not supported, skipping",
groups[i].id, buf);
continue;
}
if (!fst_cfgmgr_is_mux_managed(groups[i].id)) {
fst_mgr_printf(MSG_DEBUG,
"Group %s mux is unmanaged, skipping",
groups[i].id);
continue;
}
if (fst_cfgmgr_get_mux_ifname(groups[i].id, buf, sizeof(buf)-1) <= 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux name for %s",
groups[i].id);
goto error_muxname;
}
icnt = fst_ini_config_get_group_ifaces(fstcfg.handle,
&groups[i], &ifaces);
if (icnt < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot read interfaces for %s",
groups[i].id);
goto error_ifaces;
}
enslaved_any = FALSE;
for (j = 0; j < icnt; j++) {
if (enslave && ifaces[j].manual_enslave)
continue;
res = fst_iface_enslave(&groups[i], ifaces[j].name, enslave);
if (res < 0)
goto error_enslave;
enslaved_any = TRUE;
}
if (enslaved_any) {
res = fst_cfgmgr_update_txqueuelen(&groups[i]);
if (res)
goto error_set_iface;
fst_mgr_printf(MSG_DEBUG, "Setting bonding iface %s %s",
buf, enslave ? "up":"down");
if (_set_iface_up(sock, buf, enslave) < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot set iface %s",
buf);
goto error_set_iface;
}
}
free(ifaces);
}
free(groups);
return 0;
error_set_iface:
error_enslave:
free(ifaces);
error_ifaces:
error_muxname:
free(groups);
error_groups:
error_handle:
return -1;
}
static int bonding_ifaces_prepare()
{
return do_bonding_operations(TRUE);
}
static int bonding_ifaces_cleanup()
{
return do_bonding_operations(FALSE);
}
static int group_sessions_cleanup(const struct fst_group_info *gi)
{
uint32_t *sids = NULL;
int n, i, res = 0;
n = fst_get_sessions(gi, &sids);
if (n < 0) {
fst_mgr_printf(MSG_WARNING, "cannot get sessions for group %s",
gi->id);
return 0;
}
for (i = 0; i < n; i++) {
if (fst_session_remove(sids[i])) {
fst_mgr_printf(MSG_ERROR, "cannot remove session %u",
sids[i]);
res = -1;
}
}
fst_free(sids);
return res;
}
static int group_detach_all(const struct fst_group_info *group)
{
struct fst_iface_info *ifaces;
int i, res;
res = fst_get_group_ifaces(group, &ifaces);
if (res < 0) {
fst_mgr_printf(MSG_ERROR,
"Cannot get ifaces for group %s", group->id);
return -1;
}
for (i = 0; i < res; i++) {
if (fst_detach_iface(&ifaces[i]))
fst_mgr_printf(MSG_WARNING,
"Error detaching interface %s", ifaces[i].name);
}
fst_free(ifaces);
return 0;
}
int fst_cfgmgr_init(enum fst_config_method m, void *ctx)
{
if ((fstcfg.skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fst_mgr_printf(MSG_ERROR, "cannot open socket: %s",
strerror(errno));
return -1;
}
fstcfg.method = m;
switch (m) {
case FST_CONFIG_CLI:
fstcfg.handle = NULL;
break;
case FST_CONFIG_INI:
fstcfg.handle = fst_ini_config_init((const char*)ctx);
if (fstcfg.handle == NULL) {
fst_mgr_printf(MSG_ERROR, "Cannot initialize config");
return -1;
}
if(bonding_ifaces_prepare()) {
fst_mgr_printf(MSG_ERROR, "Cannot prepare bonding ifaces");
return -1;
}
break;
default:
fst_mgr_printf(MSG_ERROR, "Invalid config method %d", m);
return -1;
}
return 0;
}
void fst_cfgmgr_deinit()
{
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
bonding_ifaces_cleanup();
fst_ini_config_deinit(fstcfg.handle);
fstcfg.handle = NULL;
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
break;
}
close(fstcfg.skfd);
}
int fst_cfgmgr_get_groups(struct fst_group_info **groups)
{
int res;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = fst_get_groups(groups);
if (res < 0)
fst_mgr_printf(MSG_ERROR, "Cannot get groups");
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_groups(fstcfg.handle, groups);
break;
default:
fst_mgr_printf(MSG_ERROR, "Cannot get groups in current config");
res = -1;
}
return res;
}
int fst_cfgmgr_get_ctrl_iface(char *buf, int size)
{
int res = -1;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_ctrl_iface(fstcfg.handle, buf, size);
break;
default:
fst_mgr_printf(MSG_ERROR,
"Cannot get ctrl_path in current config");
}
return res;
}
int fst_cfgmgr_get_group_ifaces(const struct fst_group_info *group,
struct fst_iface_info **ifaces)
{
int res;
fst_mgr_printf(MSG_INFO, "group: %s", group->id);
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = fst_get_group_ifaces(group, ifaces);
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_group_ifaces(fstcfg.handle,
group, ifaces);
break;
default:
fst_mgr_printf(MSG_ERROR, "Cannot get ifaces in current config");
res = -1;
}
return res;
}
int fst_cfgmgr_get_iface_group_cipher(const struct fst_iface_info *iface,
char *buf, int len)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = 0;
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_iface_group_cipher(fstcfg.handle, iface,
buf, len);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_get_iface_pairwise_cipher(const struct fst_iface_info *iface,
char *buf, int len)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = 0;
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_iface_pairwise_cipher(fstcfg.handle, iface,
buf, len);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_get_iface_hw_mode(const struct fst_iface_info *iface,
char *buf, int len)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = 0;
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_iface_hw_mode(fstcfg.handle, iface,
buf, len);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_get_iface_channel(const struct fst_iface_info *iface,
char *buf, int len)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = 0;
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_iface_channel(fstcfg.handle, iface,
buf, len);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_on_iface_init(const struct fst_group_info *group,
struct fst_iface_info *iface)
{
int res = 0;
fst_mgr_printf(MSG_INFO, "group: %s", group->id);
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_attach_iface(group, iface);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_on_iface_deinit(struct fst_iface_info *iface)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_detach_iface(iface);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_on_global_init(void)
{
struct fst_group_info *groups;
int i, res = 0;
fst_mgr_printf(MSG_INFO, "enter");
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
/* Remove existing configuration */
res = fst_get_groups(&groups);
if (res < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get groups");
return -1;
}
for (i=0; i < res; i++) {
group_sessions_cleanup(&groups[i]);
group_detach_all(&groups[i]);
}
if (res)
fst_free(groups);
res = fst_rate_upgrade_init(fstcfg.handle);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
void fst_cfgmgr_on_global_deinit(void)
{
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
fst_rate_upgrade_deinit();
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
break;
}
}
int fst_cfgmgr_on_group_init(const struct fst_group_info *group)
{
if (group_sessions_cleanup(group))
return -1;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
if (fst_rate_upgrade_add_group(group))
return -1;
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
break;
}
return 0;
}
int fst_cfgmgr_on_group_deinit(const struct fst_group_info *group)
{
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
if (fst_rate_upgrade_del_group(group))
return -1;
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
return -1;
}
return 0;
}
int fst_cfgmgr_on_connect(struct fst_group_info *group, const char *iface,
const u8* addr)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_rate_upgrade_on_connect(group, iface, addr);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_on_disconnect(struct fst_group_info *group, const char *iface,
const u8* addr)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_rate_upgrade_on_disconnect(group, iface, addr);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
void fst_cfgmgr_on_switch_completed(const struct fst_group_info *group,
const char *old_iface, const char *new_iface, const u8* peer_addr)
{
if (fstcfg.method != FST_CONFIG_INI)
return;
fst_rate_upgrade_on_switch_completed(group, old_iface,
new_iface, peer_addr);
}
int fst_cfgmgr_get_mux_type(const char *gname, char *buf, int blen)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = 0;
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_mux_type(fstcfg.handle, gname, buf, blen);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_get_mux_ifname(const char *gname, char *buf, int blen)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
os_strlcpy(buf, gname, blen);
res = os_strlen(buf);
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_mux_ifname(fstcfg.handle, gname,
buf, blen);
if (res == 0) {
/* Fallback to mux==group_name if no mux name key */
os_strlcpy(buf, gname, blen);
res = os_strlen(buf);
}
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_get_l2da_ap_default_ifname(const char *gname, char *buf,
int blen)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
res = fst_ini_config_get_l2da_ap_default_ifname(fstcfg.handle, gname,
buf, blen);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
Boolean fst_cfgmgr_is_mux_managed(const char *gname)
{
Boolean res = FALSE;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
res = FALSE;
case FST_CONFIG_INI:
res = fst_ini_config_is_mux_managed(fstcfg.handle, gname);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = FALSE;
break;
}
return res;
}
int fst_cfgmgr_get_rate_upgrade_master(const char *gname, char *buf, int blen)
{
int res = 0;
char *sres;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
break;
case FST_CONFIG_INI:
sres = fst_ini_config_get_rate_upgrade_master(fstcfg.handle, gname);
if (!sres)
break;
res = os_strlcpy(buf, sres, blen);
free(sres);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_set_mux_ifname(const char *gname, const char *newname)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
/* not supported */
res = -1;
break;
case FST_CONFIG_INI:
res = fst_ini_config_set_mux_ifname(fstcfg.handle, gname,
newname);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
int fst_cfgmgr_rename_interface(const char *gname, const char *ifname, const char *newifname)
{
int res = 0;
switch (fstcfg.method) {
case FST_CONFIG_CLI:
/* not supported */
res = -1;
break;
case FST_CONFIG_INI:
res = fst_ini_config_rename_interface(fstcfg.handle, gname, ifname, newifname);
if (res)
break;
fst_rate_upgrade_rename_interface(gname, ifname, newifname);
break;
default:
fst_mgr_printf(MSG_ERROR, "Wrong config method");
res = -1;
break;
}
return res;
}
void fst_cfgmgr_on_scan_started(const struct fst_group_info *group, const char *iface)
{
if (fstcfg.method != FST_CONFIG_INI)
return;
fst_rate_upgrade_on_scan_started(group, iface);
}
void fst_cfgmgr_on_scan_completed(const struct fst_group_info *group, const char *iface)
{
if (fstcfg.method != FST_CONFIG_INI)
return;
fst_rate_upgrade_on_scan_completed(group, iface);
}
void fst_cfgmgr_on_signal_change(const struct fst_group_info *group, const char *iface)
{
if (fstcfg.method != FST_CONFIG_INI)
return;
fst_rate_upgrade_on_signal_change(group, iface);
}

View File

@@ -0,0 +1,105 @@
/*
* FST Manager: FST Configuration Manager
*
* Copyright (c) 2015-2016,2020 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_FSTCFGMGR_H__
#define __FST_FSTCFGMGR_H__
#include "utils/common.h"
#include "fst_ctrl.h"
#ifdef __cplusplus
extern "C"
{
#endif
enum fst_config_method {
FST_CONFIG_CLI,
FST_CONFIG_INI,
FST_CONFIG_MAX
};
int fst_cfgmgr_init(enum fst_config_method m, void *ctx);
void fst_cfgmgr_deinit();
int fst_cfgmgr_get_ctrl_iface(char *buf, int size);
int fst_cfgmgr_get_group_ifaces(const struct fst_group_info *group,
struct fst_iface_info **ifaces);
int fst_cfgmgr_get_groups(struct fst_group_info **groups);
int fst_cfgmgr_get_iface_group_cipher(const struct fst_iface_info *iface,
char *buf, int len);
int fst_cfgmgr_get_iface_pairwise_cipher(const struct fst_iface_info *iface,
char *buf, int len);
int fst_cfgmgr_get_iface_hw_mode(const struct fst_iface_info *iface,
char *buf, int len);
int fst_cfgmgr_get_iface_channel(const struct fst_iface_info *iface,
char *buf, int len);
int fst_cfgmgr_on_global_init(void);
void fst_cfgmgr_on_global_deinit(void);
int fst_cfgmgr_on_group_init(const struct fst_group_info *group);
int fst_cfgmgr_on_group_deinit(const struct fst_group_info *group);
int fst_cfgmgr_on_iface_init(const struct fst_group_info *group,
struct fst_iface_info *iface);
int fst_cfgmgr_on_iface_deinit(struct fst_iface_info *iface);
int fst_cfgmgr_on_connect(struct fst_group_info *group, const char *iface,
const u8* addr);
int fst_cfgmgr_on_disconnect(struct fst_group_info *group, const char *iface,
const u8* addr);
void fst_cfgmgr_on_switch_completed(const struct fst_group_info *group,
const char *old_iface, const char *new_iface, const u8* peer_addr);
int fst_cfgmgr_get_mux_type(const char *gname, char *buf, int blen);
int fst_cfgmgr_get_mux_ifname(const char *gname, char *buf, int blen);
int fst_cfgmgr_get_l2da_ap_default_ifname(const char *gname, char *buf,
int blen);
Boolean fst_cfgmgr_is_mux_managed(const char *gname);
int fst_cfgmgr_get_rate_upgrade_master(const char *gname, char *buf, int blen);
int fst_cfgmgr_set_mux_ifname(const char *gname, const char *newname);
int fst_cfgmgr_rename_interface(const char *gname, const char *ifname, const char *newifname);
int set_iface_up(const char *ifname, Boolean up);
int get_iface_flags(const char *ifname, short int *flags);
int fst_iface_enslave(struct fst_group_info *ginfo, const char *ifname, Boolean enslave);
int fst_set_mac_address(struct fst_group_info *ginfo, const u8 *mac);
void fst_cfgmgr_on_scan_started(const struct fst_group_info *group, const char *iface);
void fst_cfgmgr_on_scan_completed(const struct fst_group_info *group, const char *iface);
void fst_cfgmgr_on_signal_change(const struct fst_group_info *group, const char *iface);
int fst_cfgmgr_update_txqueuelen(const struct fst_group_info *group);
int fst_cfgmgr_set_mux_iface_up(const struct fst_group_info *group, Boolean up);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FST_FSTCONF_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,281 @@
/*
* FST Manager: hostapd/wpa_supplicant control interface wrapper definitions
*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_CTRL_H__
#define __FST_CTRL_H__
#include <errno.h>
#include "fst/fst_ctrl_aux.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* fst_notification_cb_func - FST notification callback function
* @cb_ctx: %ntfy_cb_ctx as passed to fst_set_notify_cb()
* @group_id: FST group ID
* @session_id: FST session ID
* @event_type: kind of FST event for the call
* @extra: event-specific auxiliary information.
* TODO: Define extra information for each event type
*/
typedef void (*fst_notification_cb_func)(void *cb_ctx,
u32 session_id,
enum fst_event_type event_type,
void *extra);
/**
* fst_set_notify_cb - set FST control callback
* @ntfy_cb: FST notification callback function, %NULL to disable
* @ntfy_cb_ctx: FST notification callback function's context to be passed to %ntfy_cb
* Returns: 0 if success or negative error code
*/
int fst_set_notify_cb(fst_notification_cb_func ntfy_cb, void *ntfy_cb_ctx);
struct fst_group_info {
char id[FST_MAX_GROUP_ID_SIZE];
};
/**
* fst_get_groups - get list of FST groups
* @groups: Array of fst_group_info elements allocated by the function.
* The array should be freed by caller.
* Returns: Number of allocated elements if success or negative error code
*/
int fst_get_groups(struct fst_group_info **groups);
struct fst_iface_info{
char name[FST_MAX_INTERFACE_SIZE];
u8 addr[ETH_ALEN];
u8 priority;
u32 llt;
u8 manual_enslave;
};
/**
* fst_get_iface_peers - get list of connected peers for this interface
* @group: FST group info from fst_get_groups()
* @iface: FST interface info fst_get_group_ifaces()
* @peers: The list of peers MAC addresses allocated by the function.
* The array should be freed by caller.
* Returns: Number of allocated elements if success or negative error code
*/
int fst_get_iface_peers(const struct fst_group_info *group,
struct fst_iface_info *iface, uint8_t **peers);
/**
* fst_get_peer_mbies - get the hexadecimal dump of the peer's MBIEs on a given
* interface
* @ifname: FST interface name
* @peer: The peer's MAC address
* @mbies: The hexadecimal dump of the peer's MBIEs on the given interface
* if not NULL. The array should be freed by caller.
* Returns: Number of allocated bytes if success or negative error code
*/
int fst_get_peer_mbies(const char *ifname, const uint8_t *peer, char **mbies);
/**
* fst_get_group_ifaces - get interfaces for the provided group
* @group_id: FST group ID from fst_get_groups()
* @ifaces: Array of fst_iface_info elements allocated by the function.
* The array should be freed by caller.
* Returns: Number of allocated elements if success or negative error code
*/
int fst_get_group_ifaces(const struct fst_group_info *group,
struct fst_iface_info **ifaces);
/**
* fst_detach_iface - Detaches FST interface
* @iface: FST interface info for the interface to be detached
*
* Retunrs: 0 if success or a negative error code
*/
int fst_detach_iface(const struct fst_iface_info *iface);
/**
* fst_attach_iface - Attaches FST interface
* @group: FST group info for the group the interface to be attached to
* @iface: FST interface info for the interface to be attached
*
* Retunrs: 0 if success or a negative error code
*/
int fst_attach_iface(const struct fst_group_info *group,
const struct fst_iface_info *iface);
/**
* fst_is_supplicant - Returns true if the hostap application is
* the wpa_supplicant, FALSE - if the hostapd
*/
Boolean fst_is_supplicant(void);
/**
* fst_add_iface - Add interfaces to Hostap
* @master: Master interface name
* @iface: Interface name
* @acl_file: ACL file name for accept_mac_file (see hostapd.conf), can be NULL
* @ctrl_interface: Control interface path, can be NULL
*/
int fst_add_iface(const char *master, const struct fst_iface_info *iface,
const char *acl_file, const char *ctrl_interface);
/**
* fst_del_iface - Delete interface from Hostap
* @iface: Interface name
*/
int fst_del_iface(const struct fst_iface_info *iface);
/**
* fst_dup_connection - Copy the connection params from master interface and
* initiate a hostap connection for the interface iface
* @iface: Interface info for the interface to connect
* @master: Master interface name the connection parameters to be copied from
* @addr: Address (BSSID) to connect to
* @freq: Frequency to scan for the AP
* @acl_file: ACL file name for accept_mac_file (see hostapd.conf), can be NULL
*/
int fst_dup_connection(const struct fst_iface_info *iface,
const char *master, const u8 *addr, u32 freq, const char *acl_file);
/**
* fst_dedup_connection - disallow connection on interface iface
* @iface: Interface
* @acl_file: ACL file name accept_mac_file (see hostapd.conf), can be NULL
*/
int fst_dedup_connection(const struct fst_iface_info *iface, const char *acl_file);
/**
* fst_disconnect_peer - Disconnects from peer over specific interface
* @ifname: Interface to disconnect
* @peer_addr: peer to disconnect from
*/
int fst_disconnect_peer(const char *ifname, const u8 *peer_addr);
/**
* fst_get_sessions - Iterate FST session within a group
* @group_id: FST group ID from fst_get_groups()
* @sessions: Array of fst_sessions allocated by the function.
* The array should be freed by caller.
* Returns: Number of allocated elements if success or negative error code
*/
int fst_get_sessions(const struct fst_group_info *group, u32 **sessions);
struct fst_session_info
{
u8 old_peer_addr[ETH_ALEN];
u8 new_peer_addr[ETH_ALEN];
char old_ifname[FST_MAX_INTERFACE_SIZE];
char new_ifname[FST_MAX_INTERFACE_SIZE];
u32 llt;
enum fst_session_state state;
u32 session_id;
};
/**
* fst_free - free an array allocated by fst_get_groups, fst_get_group_ifaces or
* fst_get_sessions
* @p: an array allocated by fst_get_groups, fst_get_group_ifaces,
* fst_get_iface_peers or fst_get_sessions
*/
void fst_free(void *p);
/**
* fst_session_get_info - Get FST session within a group
* @session_id: FST Session id as received from fst_get_sessions.
* @info: structure to fill if call succeeds
* Returns: 0 on success, negative error codes on errors
*/
int fst_session_get_info(u32 session_id, struct fst_session_info *info);
/**
* fst_session_add - Create FST session context
* @session_id: FST Session id as received from fst_get_sessions.
* Returns: 0 on success, negative error codes on errors
*/
int fst_session_add(const char * group_id, u32 * session_id);
/**
* fst_session_remove - Remove FST session
* @session_id: FST Session id as received from fst_get_sessions.
* Returns: 0 on success, supported error codes on failure.
*/
int fst_session_remove(u32 session_id);
/**
* fst_session_set - Set FST session parameter
* @session_id: FST Session id as received from fst_get_sessions.
* @pname: parameter name to set
* @pval: parameter value to set
* Returns: 0 on success, negative error codes on failures
*/
int fst_session_set(u32 session_id, const char *pname, const char * pval);
/**
* fst_session_initiate - Initiate FST session
* @session_id: FST Session id as received from fst_get_sessions.
* Returns: 0 on success, negative error code on failure
*/
int fst_session_initiate(u32 session_id);
/**
* fst_session_respond - Respond to FST session request
* @session_id: FST Session id as received from fst_get_sessions.
* @response_status: response status string
* Returns: 0 on success, supported error codes on failure.
*/
int fst_session_respond(u32 session_id, const char *response_status);
/**
* fst_session_transfer - Transfer established FST session
* @session_id: FST Session id as received from fst_get_sessions.
* Returns: 0 on success, supported error codes on failure.
*/
int fst_session_transfer(u32 session_id);
/**
* fst_session_teardown - Tear down established FST session
* @session_id: FST Session id as received from fst_get_sessions.
* Returns: 0 on success, supported error codes on failure.
*/
int fst_session_teardown(u32 session_id);
int fst_signal_monitor(const char *iface, int thresh, int hyst);
void fst_ctrl_bss_flush(const char *iface);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FST_CTRL_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,967 @@
/*
* FST Manager: INI configuration file parser
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <string.h>
#include <stdlib.h>
#include "utils/list.h"
#include "fst_ini_conf.h"
#include "ini.h"
#define FST_MGR_COMPONENT "INI_CONF"
#include "fst_manager.h"
struct fst_ini_config
{
char *filename;
struct cfg_cache *cache;
};
struct cfg_ctx {
const char *section;
const char *name;
char *buffer;
int buflen;
Boolean is_found;
};
/*
* FST Manager standalone configuration
*/
/* matches the ini file limit */
#define MAX_CFG_STRING 80
struct cfg_cache {
char ctrl_iface[MAX_CFG_STRING];
char slave_ctrl_interface[MAX_CFG_STRING];
struct dl_list groups;
};
struct cfg_group_info {
char name[FST_MAX_GROUP_ID_SIZE];
char rate_upgrade_master[MAX_CFG_STRING];
char rate_upgrade_acl_fname[MAX_CFG_STRING];
char mux_type[MAX_CFG_STRING];
char mux_ifname[MAX_CFG_STRING];
char l2da_ap_default_ifname[MAX_CFG_STRING];
Boolean is_mux_managed;
int txqueuelen;
struct dl_list ifaces;
struct dl_list list;
};
struct cfg_iface_info {
struct fst_iface_info info;
char group_cipher[MAX_CFG_STRING];
char pairwise_cipher[MAX_CFG_STRING];
char hw_mode[MAX_CFG_STRING];
char channel[MAX_CFG_STRING];
struct dl_list list;
};
int fst_ini_config_get_ctrl_iface(struct fst_ini_config *h, char *buf, int size)
{
if (!h->cache || !h->cache->ctrl_iface[0]) {
fst_mgr_printf(MSG_ERROR,
"No ctrl_iface found in fst_manager config");
return -1;
}
os_strlcpy(buf, h->cache->ctrl_iface, size);
return 0;
}
static struct cfg_group_info *fst_ini_find_cfg_group(struct fst_ini_config *h,
const char *id)
{
struct cfg_group_info *item;
if (!h->cache)
return NULL;
dl_list_for_each(item, &h->cache->groups,
struct cfg_group_info, list) {
if (!strncmp(item->name, id, FST_MAX_GROUP_ID_SIZE))
return item;
}
return NULL;
}
int fst_ini_config_get_group_ifaces(struct fst_ini_config *h,
const struct fst_group_info *group, struct fst_iface_info **ifaces)
{
struct cfg_group_info *cginfo = NULL;
struct cfg_iface_info *item;
int i, cnt;
if (!h->cache) {
fst_mgr_printf(MSG_ERROR, "no config cache");
return -1;
}
cginfo = fst_ini_find_cfg_group(h, group->id);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return -1;
}
cnt = dl_list_len(&cginfo->ifaces);
if (!cnt) {
fst_mgr_printf(MSG_ERROR,
"No interfaces found for group %s", group->id);
return -1;
}
*ifaces = (struct fst_iface_info*)os_zalloc(
sizeof(struct fst_iface_info) * cnt);
if (*ifaces == NULL) {
fst_mgr_printf(MSG_ERROR,
"Cannot allocate memory for interface");
return -1;
}
item = dl_list_first(&cginfo->ifaces, struct cfg_iface_info, list);
for (i = 0; i < cnt; i++) {
(*ifaces)[i] = item->info;
item = dl_list_entry(item->list.next, struct cfg_iface_info,
list);
}
return cnt;
}
int fst_ini_config_get_groups(struct fst_ini_config *h,
struct fst_group_info **groups)
{
int i, cnt;
struct cfg_group_info *item;
*groups = NULL;
if (!h->cache) {
fst_mgr_printf(MSG_ERROR, "no config cache");
return -1;
}
cnt = dl_list_len(&h->cache->groups);
if (cnt == 0) {
fst_mgr_printf(MSG_ERROR,
"No groups defined in config");
return -1;
}
*groups = (struct fst_group_info*)malloc(
sizeof(struct fst_group_info) * cnt);
if (*groups == NULL) {
fst_mgr_printf(MSG_ERROR,"Cannot allocate memory for groups");
return -1;
}
item = dl_list_first(&h->cache->groups, struct cfg_group_info, list);
for (i = 0; i < cnt; i++) {
os_strlcpy((*groups)[i].id, item->name,
sizeof((*groups)[i].id));
item = dl_list_entry(item->list.next, struct cfg_group_info,
list);
}
return cnt;
}
char *fst_ini_config_get_rate_upgrade_master(struct fst_ini_config *h,
const char *groupname)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, groupname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return NULL;
}
if (!cginfo->rate_upgrade_master[0])
return NULL;
return strdup(cginfo->rate_upgrade_master);
}
char *fst_ini_config_get_rate_upgrade_acl_fname(struct fst_ini_config *h,
const char *groupname)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, groupname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return NULL;
}
if (!cginfo->rate_upgrade_acl_fname[0])
return NULL;
return strdup(cginfo->rate_upgrade_acl_fname);
}
int fst_ini_config_get_mux_type(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return 0;
}
os_strlcpy(buf, cginfo->mux_type, buflen);
return strlen(buf);
}
int fst_ini_config_get_mux_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return 0;
}
os_strlcpy(buf, cginfo->mux_ifname, buflen);
return strlen(buf);
}
int fst_ini_config_get_l2da_ap_default_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return 0;
}
os_strlcpy(buf, cginfo->l2da_ap_default_ifname, buflen);
return strlen(buf);
}
Boolean fst_ini_config_is_mux_managed(struct fst_ini_config *h, const char *gname)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return FALSE;
}
return cginfo->is_mux_managed;
}
static struct cfg_iface_info *fst_ini_find_cfg_iface(struct fst_ini_config *h,
const char *ifname)
{
struct cfg_group_info *cginfo;
struct cfg_iface_info *ifinfo;
if (!h->cache)
return NULL;
dl_list_for_each(cginfo, &h->cache->groups,
struct cfg_group_info, list) {
dl_list_for_each(ifinfo, &cginfo->ifaces,
struct cfg_iface_info, list) {
if (!strncmp(ifname, ifinfo->info.name,
FST_MAX_INTERFACE_SIZE))
return ifinfo;
}
}
return NULL;
}
int fst_ini_config_get_iface_group_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
struct cfg_iface_info *ifinfo;
ifinfo = fst_ini_find_cfg_iface(h, iface->name);
if (!ifinfo) {
fst_mgr_printf(MSG_ERROR, "interface not found");
return 0;
}
os_strlcpy(buf, ifinfo->group_cipher, len);
return strlen(buf);
}
int fst_ini_config_get_iface_pairwise_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
struct cfg_iface_info *ifinfo;
ifinfo = fst_ini_find_cfg_iface(h, iface->name);
if (!ifinfo) {
fst_mgr_printf(MSG_ERROR, "interface not found");
return 0;
}
os_strlcpy(buf, ifinfo->pairwise_cipher, len);
return strlen(buf);
}
int fst_ini_config_get_iface_hw_mode(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
struct cfg_iface_info *ifinfo;
ifinfo = fst_ini_find_cfg_iface(h, iface->name);
if (!ifinfo) {
fst_mgr_printf(MSG_ERROR, "interface not found");
return 0;
}
os_strlcpy(buf, ifinfo->hw_mode, len);
return strlen(buf);
}
int fst_ini_config_get_iface_channel(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
struct cfg_iface_info *ifinfo;
ifinfo = fst_ini_find_cfg_iface(h, iface->name);
if (!ifinfo) {
fst_mgr_printf(MSG_ERROR, "interface not found");
return 0;
}
os_strlcpy(buf, ifinfo->channel, len);
return strlen(buf);
}
int fst_ini_config_get_txqueuelen(struct fst_ini_config *h, const char *gname)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return -1;
}
return cginfo->txqueuelen;
}
int fst_ini_config_get_slave_ctrl_interface(struct fst_ini_config *h, char *buf, int len)
{
if (!h->cache || !h->cache->ctrl_iface[0]) {
fst_mgr_printf(MSG_ERROR,
"No slave_ctrl_iface found in fst_manager config");
return 0;
}
os_strlcpy(buf, h->cache->slave_ctrl_interface, len);
return 0;
}
int fst_ini_config_set_mux_ifname(struct fst_ini_config *h,
const char *gname, const char *newname)
{
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return -1;
}
os_strlcpy(cginfo->mux_ifname, newname, sizeof(cginfo->mux_ifname));
return 0;
}
int fst_ini_config_rename_interface(struct fst_ini_config *h,
const char *gname, const char *ifname, const char *newname)
{
struct cfg_iface_info *ifinfo;
struct cfg_group_info *cginfo;
cginfo = fst_ini_find_cfg_group(h, gname);
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "group not found");
return -1;
}
ifinfo = fst_ini_find_cfg_iface(h, newname);
if (ifinfo) {
fst_mgr_printf(MSG_ERROR, "new interface %s already exists",
newname);
return -1;
}
ifinfo = fst_ini_find_cfg_iface(h, ifname);
if (!ifinfo) {
fst_mgr_printf(MSG_ERROR, "interface %s not found", ifname);
return -1;
}
os_strlcpy(ifinfo->info.name, newname, sizeof(ifinfo->info.name));
if (!os_strcmp(cginfo->rate_upgrade_master, ifname)) {
os_strlcpy(cginfo->rate_upgrade_master, newname, sizeof(cginfo->rate_upgrade_master));
}
return 0;
}
/*
* Reading the INI file
*/
static int ini_handler(void* user, const char* section, const char* name,
const char* value)
{
struct cfg_ctx *ctx = (struct cfg_ctx*)user;
if (!ctx->is_found) {
if (strncmp(section, ctx->section, strlen(section)) == 0 &&
strncmp(name, ctx->name, strlen(name)) == 0) {
ctx->is_found = TRUE;
if (ctx->buffer && ctx->buflen) {
os_strlcpy(ctx->buffer, value, ctx->buflen);
}
}
}
return 1;
}
static int parse_csv(char *string, char **tokens, int tokenslen)
{
const char *delim = " ,\t";
char *tokbuf;
int count = 0;
char *token = strtok_r(string, delim, &tokbuf);
while (token != NULL && count < tokenslen) {
count++;
*tokens++ = token;
token = strtok_r(NULL, delim, &tokbuf);
}
return count;
}
static Boolean fst_ini_config_read(struct fst_ini_config *h, const char *s,
const char *k, char *buf, int buflen)
{
struct cfg_ctx ctx;
ctx.section = s;
ctx.name = k;
ctx.buffer = buf;
ctx.buflen = buflen;
ctx.is_found = FALSE;
if (ini_parse(h->filename, ini_handler, &ctx) < 0) {
fst_mgr_printf(MSG_ERROR, "Error parsing configuration file %s",
h->filename);
}
return ctx.is_found;
}
static int fst_ini_cache_config(struct fst_ini_config *h);
static void fst_ini_free_config_cache(struct cfg_cache *cache);
struct fst_ini_config *fst_ini_config_init(const char *filename)
{
struct fst_ini_config *h = (struct fst_ini_config*)os_zalloc(
sizeof(struct fst_ini_config));
if (h == NULL) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate memory for config");
return NULL;
}
h->filename = strdup(filename);
if (h->filename == NULL) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate memory for filename");
goto out_err;
}
if (fst_ini_cache_config(h) < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot cache ini configuration");
goto out_err;
}
return h;
out_err:
fst_ini_config_deinit(h);
return NULL;
}
void fst_ini_config_deinit(struct fst_ini_config *h)
{
if (!h)
return;
fst_ini_free_config_cache(h->cache);
free(h->filename);
free(h);
}
/*
* FST Manager standalone configuration - used for caching only
*/
#define INI_MAX_STRING 80
#define INI_MAX_TOKENS 16
static int __fst_ini_config_get_ctrl_iface(struct fst_ini_config *h,
char *buf, int size)
{
if (!fst_ini_config_read(h, "fst_manager", "ctrl_iface",
buf, size)) {
fst_mgr_printf(MSG_ERROR,
"No ctrl_iface found in fst_manager config");
return -1;
}
return 0;
}
static int __fst_ini_config_get_group_ifaces(struct fst_ini_config *h,
const struct fst_group_info *group, struct fst_iface_info **ifaces)
{
char buf[INI_MAX_STRING+1], buf_ifaces[INI_MAX_STRING+1];
char *tokens[INI_MAX_TOKENS];
int i, cnt;
if (!fst_ini_config_read(h, (const char*)group->id, "interfaces",
buf_ifaces, INI_MAX_STRING)) {
fst_mgr_printf(MSG_ERROR,
"No interfaces key for group %s", group->id);
return -1;
}
cnt = parse_csv(buf_ifaces, tokens, INI_MAX_TOKENS);
if (cnt == 0) {
fst_mgr_printf(MSG_ERROR,
"No interfaces found for group %s", group->id);
return -1;
}
fst_mgr_printf(MSG_INFO,"%d interfaces found", cnt);
*ifaces = (struct fst_iface_info*)os_zalloc(
sizeof(struct fst_iface_info) * cnt);
if (*ifaces == NULL) {
fst_mgr_printf(MSG_ERROR,
"Cannot allocate memory for interface");
return -1;
}
for (i = 0; i < cnt; i++) {
os_strlcpy((*ifaces)[i].name, tokens[i], sizeof((*ifaces)[i].name));
if (fst_ini_config_read(h, (const char*)tokens[i], "priority",
buf, INI_MAX_STRING))
(*ifaces)[i].priority = strtoul(buf, NULL, 0);
if (fst_ini_config_read(h, (const char*)tokens[i], "default_llt",
buf, INI_MAX_STRING))
(*ifaces)[i].llt = strtoul(buf, NULL, 0);
if (fst_ini_config_read(h, (const char*)tokens[i], "manual_enslave",
buf, INI_MAX_STRING))
(*ifaces)[i].manual_enslave = strtoul(buf, NULL, 0);
fst_mgr_printf(MSG_DEBUG,
"iface %s (pri=%d, llt=%d manual_enslave=%d) has been parsed",
(*ifaces)[i].name, (*ifaces)[i].priority, (*ifaces)[i].llt, (*ifaces)[i].manual_enslave);
}
return cnt;
}
static int __fst_ini_config_get_groups(struct fst_ini_config *h,
struct fst_group_info **groups)
{
char buf[INI_MAX_STRING+1];
char *tokens[INI_MAX_TOKENS];
int i, cnt;
*groups = NULL;
if (!fst_ini_config_read(h, "fst_manager", "groups",
buf, INI_MAX_STRING)) {
fst_mgr_printf(MSG_ERROR,
"No groups key found in fst_manager config");
return -1;
}
cnt = parse_csv(buf, tokens, INI_MAX_TOKENS);
if (cnt == 0) {
fst_mgr_printf(MSG_ERROR,
"No groups defined in config");
return -1;
}
*groups = (struct fst_group_info*)malloc(
sizeof(struct fst_group_info) * cnt);
if (*groups == NULL) {
fst_mgr_printf(MSG_ERROR,"Cannot allocate memory for groups");
return -1;
}
for (i = 0; i < cnt; i++) {
os_strlcpy((*groups)[i].id, tokens[i], sizeof((*groups)[i].id));
fst_mgr_printf(MSG_DEBUG,"Config: group %s has been parsed", tokens[i]);
}
return cnt;
}
static char *__fst_ini_config_get_rate_upgrade_master(struct fst_ini_config *h,
const char *groupname)
{
char buf[INI_MAX_STRING+1];
if(!fst_ini_config_read(h, groupname, "rate_upgrade_master", buf,
INI_MAX_STRING))
return NULL;
return strdup(buf);
}
static char *__fst_ini_config_get_rate_upgrade_acl_fname(struct fst_ini_config *h,
const char *groupname)
{
char buf[INI_MAX_STRING+1];
if(!fst_ini_config_read(h, groupname, "rate_upgrade_acl_file", buf,
INI_MAX_STRING))
return NULL;
return strdup(buf);
}
/* this is part of the public API, it does not access the INI directly */
int fst_ini_config_get_group_slave_ifaces(struct fst_ini_config *h,
const struct fst_group_info *group, const char *master,
struct fst_iface_info **ifaces)
{
int i, cnt;
fst_mgr_printf(MSG_INFO,"group %s master %s", group->id, master);
cnt = fst_ini_config_get_group_ifaces(h, group, ifaces);
if (cnt < 0)
return cnt;
for (i=0; i < cnt; i++) {
if (!strncmp((*ifaces)[i].name, master, strlen(master))) {
/* Skip the master interface */
cnt--;
if (i < cnt)
os_memmove(&(*ifaces)[i], &(*ifaces)[i+1],
(cnt-i) * sizeof(struct fst_iface_info));
return cnt;
}
}
return cnt;
}
static int __fst_ini_config_get_mux_type(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
if(!fst_ini_config_read(h, gname, "mux_type", buf, buflen))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_mux_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
if(!fst_ini_config_read(h, gname, "mux_ifname", buf, buflen))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_l2da_ap_default_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen)
{
if(!fst_ini_config_read(h, gname, "l2da_ap_default_ifname", buf, buflen))
return 0;
return strlen(buf);
}
static Boolean __fst_ini_config_is_mux_managed(struct fst_ini_config *h, const char *gname)
{
char buf[INI_MAX_STRING+1];
if(!fst_ini_config_read(h, gname, "mux_managed", buf,
INI_MAX_STRING))
return FALSE;
if (buf[0] == '1' || buf[0] == 'y' || buf[0] == 'Y')
return TRUE;
else if (buf[0] == '0' || buf[0] == 'n' || buf[0] == 'N')
return FALSE;
else {
fst_mgr_printf(MSG_ERROR,
"mux_managed wrong boolean %s, assuming false", buf);
return FALSE;
}
}
static int __fst_ini_config_get_iface_group_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
if(!fst_ini_config_read(h, iface->name, "wpa_group", buf, len))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_iface_pairwise_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
if(!fst_ini_config_read(h, iface->name, "wpa_pairwise", buf, len))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_iface_hw_mode(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
if(!fst_ini_config_read(h, iface->name, "hw_mode", buf, len))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_iface_channel(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len)
{
if(!fst_ini_config_read(h, iface->name, "channel", buf, len))
return 0;
return strlen(buf);
}
static int __fst_ini_config_get_txqueuelen(struct fst_ini_config *h, const char *gname)
{
char buf[INI_MAX_STRING + 1];
if (!fst_ini_config_read(h, gname, "txqueuelen", buf, INI_MAX_STRING))
return -1;
return atoi(buf);
}
static int __fst_ini_config_get_slave_ctrl_interface(struct fst_ini_config *h,
char *buf, int len)
{
if(!fst_ini_config_read(h, "fst_manager", "slave_ctrl_iface_dir", buf, len))
return 0;
return strlen(buf);
}
/*
* Caching the INI file
*/
static int fst_ini_cache_iface(struct fst_ini_config *h,
struct fst_iface_info *fiinfo, struct cfg_iface_info **out_ciinfo)
{
struct cfg_iface_info *ciinfo;
ciinfo = (struct cfg_iface_info *)os_zalloc(
sizeof(struct cfg_iface_info));
if (!ciinfo) {
fst_mgr_printf(MSG_ERROR, "cache_iface: fail to allocate cfg_iface_info");
return -1;
}
ciinfo->info = *fiinfo;
__fst_ini_config_get_iface_group_cipher(h, fiinfo, ciinfo->group_cipher,
sizeof(ciinfo->group_cipher));
__fst_ini_config_get_iface_pairwise_cipher(h, fiinfo,
ciinfo->pairwise_cipher, sizeof(ciinfo->pairwise_cipher));
__fst_ini_config_get_iface_hw_mode(h, fiinfo, ciinfo->hw_mode, sizeof(ciinfo->hw_mode));
__fst_ini_config_get_iface_channel(h, fiinfo, ciinfo->channel, sizeof(ciinfo->channel));
*out_ciinfo = ciinfo;
return 0;
}
static int fst_ini_cache_ifaces(struct fst_ini_config *h,
struct fst_group_info *fginfo, struct cfg_group_info *cginfo)
{
struct fst_iface_info *ifaces = NULL;
int nof_ifaces, i, res;
struct cfg_iface_info *ifinfo = NULL;
res = __fst_ini_config_get_group_ifaces(h, fginfo, &ifaces);
if (res < 0) {
fst_mgr_printf(MSG_ERROR, "cache_ifaces: fail to get ifaces");
return -1;
}
nof_ifaces = res;
res = 0;
for (i = 0; i < nof_ifaces; i++) {
if (fst_ini_cache_iface(h, &ifaces[i], &ifinfo) < 0) {
res = -1;
break;
}
dl_list_add_tail(&cginfo->ifaces, &ifinfo->list);
}
free(ifaces);
/* on error, anything already added to cache will be freed by caller */
return res;
}
static void fst_ini_free_group_info(struct cfg_group_info *cginfo)
{
struct cfg_iface_info *ifinfo, *tmp;
if (!cginfo)
return;
dl_list_for_each_safe(ifinfo, tmp, &cginfo->ifaces,
struct cfg_iface_info, list) {
dl_list_del(&ifinfo->list);
free(ifinfo);
}
free(cginfo);
}
static int fst_ini_cache_group(
struct fst_ini_config *h, struct fst_group_info *fginfo,
struct cfg_group_info **out_cginfo)
{
struct cfg_group_info *cginfo;
char *str;
cginfo = (struct cfg_group_info *)os_zalloc(
sizeof(struct cfg_group_info));
if (!cginfo) {
fst_mgr_printf(MSG_ERROR, "fail to allocate cfg_group_info");
return -1;
}
dl_list_init(&cginfo->ifaces);
os_strlcpy(cginfo->name, fginfo->id, sizeof(cginfo->name));
str = __fst_ini_config_get_rate_upgrade_master(h, cginfo->name);
if (str) {
os_strlcpy(cginfo->rate_upgrade_master, str,
sizeof(cginfo->rate_upgrade_master));
free(str);
}
str = __fst_ini_config_get_rate_upgrade_acl_fname(h, cginfo->name);
if (str) {
os_strlcpy(cginfo->rate_upgrade_acl_fname, str,
sizeof(cginfo->rate_upgrade_acl_fname));
free(str);
}
__fst_ini_config_get_mux_type(h, cginfo->name, cginfo->mux_type,
sizeof(cginfo->mux_type));
__fst_ini_config_get_mux_ifname(h, cginfo->name, cginfo->mux_ifname,
sizeof(cginfo->mux_ifname));
__fst_ini_config_get_l2da_ap_default_ifname(h, cginfo->name,
cginfo->l2da_ap_default_ifname,
sizeof(cginfo->l2da_ap_default_ifname));
cginfo->is_mux_managed = __fst_ini_config_is_mux_managed(h, cginfo->name);
cginfo->txqueuelen = __fst_ini_config_get_txqueuelen(h, cginfo->name);
if (fst_ini_cache_ifaces(h, fginfo, cginfo) < 0)
goto out_err;
*out_cginfo = cginfo;
return 0;
out_err:
fst_ini_free_group_info(cginfo);
return -1;
}
static int fst_ini_cache_groups(struct fst_ini_config *h, struct cfg_cache *cache)
{
struct fst_group_info *groups = NULL;
struct cfg_group_info *ginfo = NULL;
int res, nof_groups, i;
res = __fst_ini_config_get_groups(h, &groups);
if (res < 0) {
fst_mgr_printf(MSG_ERROR, "fail to get groups");
return -1;
}
nof_groups = res;
res = 0;
for (i = 0; i < nof_groups; i++) {
res = fst_ini_cache_group(h, &groups[i], &ginfo);
if (res < 0)
break;
dl_list_add_tail(&cache->groups, &ginfo->list);
}
free(groups);
/* on error, anything already added to cache will be freed by caller */
return res;
}
static void fst_ini_free_config_cache(struct cfg_cache *cache)
{
struct cfg_group_info *cginfo, *tmp;
if (!cache)
return;
dl_list_for_each_safe(cginfo, tmp, &cache->groups,
struct cfg_group_info, list) {
dl_list_del(&cginfo->list);
fst_ini_free_group_info(cginfo);
}
free(cache);
}
static int fst_ini_cache_config(struct fst_ini_config *h)
{
struct cfg_cache *cache;
cache = (struct cfg_cache *)os_zalloc(sizeof(struct cfg_cache));
if (!cache) {
fst_mgr_printf(MSG_ERROR, "fail to allocate cfg_cache");
return -1;
}
dl_list_init(&cache->groups);
__fst_ini_config_get_ctrl_iface(h, cache->ctrl_iface,
sizeof(cache->ctrl_iface));
__fst_ini_config_get_slave_ctrl_interface(h,
cache->slave_ctrl_interface,
sizeof(cache->slave_ctrl_interface));
if (fst_ini_cache_groups(h, cache) < 0)
goto out_err;
h->cache = cache;
return 0;
out_err:
fst_ini_free_config_cache(cache);
return -1;
}

View File

@@ -0,0 +1,83 @@
/*
* FST Manager: INI configuration file parser
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_INI_CONF_H__
#define __FST_INI_CONF_H__
#include "utils/common.h"
#include "fst_ctrl.h"
struct fst_ini_config;
struct fst_ini_config *fst_ini_config_init(const char *filename);
void fst_ini_config_deinit(struct fst_ini_config *h);
int fst_ini_config_get_ctrl_iface(struct fst_ini_config *h,
char *buf, int size);
int fst_ini_config_get_group_ifaces(struct fst_ini_config *h,
const struct fst_group_info *group,
struct fst_iface_info **ifaces);
int fst_ini_config_get_groups(struct fst_ini_config *h,
struct fst_group_info **groups);
char *fst_ini_config_get_rate_upgrade_master(struct fst_ini_config *h,
const char *groupname);
char *fst_ini_config_get_rate_upgrade_acl_fname(struct fst_ini_config *h,
const char *groupname);
int fst_ini_config_get_group_slave_ifaces(struct fst_ini_config *h,
const struct fst_group_info *group, const char *master,
struct fst_iface_info **ifaces);
int fst_ini_config_get_mux_type(struct fst_ini_config *h,
const char *gname, char *buf, int buflen);
int fst_ini_config_get_mux_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen);
int fst_ini_config_get_l2da_ap_default_ifname(struct fst_ini_config *h,
const char *gname, char *buf, int buflen);
Boolean fst_ini_config_is_mux_managed(struct fst_ini_config *h,
const char *gname);
int fst_ini_config_get_iface_group_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len);
int fst_ini_config_get_iface_pairwise_cipher(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len);
int fst_ini_config_get_iface_hw_mode(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len);
int fst_ini_config_get_iface_channel(struct fst_ini_config *h,
const struct fst_iface_info *iface, char *buf, int len);
int fst_ini_config_get_txqueuelen(struct fst_ini_config *h, const char *gname);
int fst_ini_config_get_slave_ctrl_interface(struct fst_ini_config *h,
char *buf, int len);
int fst_ini_config_set_mux_ifname(struct fst_ini_config *h,
const char *gname, const char *newname);
int fst_ini_config_rename_interface(struct fst_ini_config *h,
const char *gname, const char *ifname, const char *newname);
#endif /* __FST_INI_CONF_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
/*
* FST Manager interface definitions
*
* Copyright (c) 2015, 2019 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_MANAGER_H__
#define __FST_MANAGER_H__
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/defs.h"
#ifndef FST_MGR_COMPONENT
#error "FST_MGR_COMPONENT has to be defined"
#endif
#define FST_MANAGER_VERSION "0.02"
#ifdef CONFIG_DBUS
#include <glib.h>
#define _fst_mgr_printf g_printerr
#else
#define _fst_mgr_printf(format, ...) wpa_printf(MSG_ERROR, format, ##__VA_ARGS__)
#endif
extern unsigned int fst_debug_level;
#include <sys/time.h>
#define fst_mgr_printf(level, format, ...) \
do { \
if ((level) >= fst_debug_level) { \
struct timeval tv = {}; \
gettimeofday(&tv, NULL); \
_fst_mgr_printf("[%08lu.%06lu] FST: " FST_MGR_COMPONENT \
": %s: " format "\n", \
(unsigned long)tv.tv_sec, \
(unsigned long)tv.tv_usec, \
__func__, ##__VA_ARGS__); \
} \
} while (0)
#ifdef __cplusplus
extern "C"
{
#endif
int fst_manager_init(void);
void fst_manager_deinit(void);
const u8 *fst_mgr_get_addr_from_mbie(struct multi_band_ie *mbie);
void fst_manager_terminate(void);
int fst_manager_enslave(const char *gname, const char* ifname, Boolean enslave);
int fst_manager_is_enslaved(const char *gname, const char* ifname,
Boolean *isEnslaved);
int fst_manager_set_mac_address(const char *ifname, const u8 *mac);
int fst_manager_set_mux_iface_name(const char *gname, const char *ifname);
int fst_manager_rename_group_interface(const char *gname, const char *ifname,
const char *newifname);
int fst_manager_session_transfer(const char *old_ifname, const u8 *peer_addr);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FST_MANAGER_H__ */

View File

@@ -0,0 +1,52 @@
/*
* FST mux interface definitions
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_MUX_H__
#define __FST_MUX_H__
#include "utils/common.h"
struct fst_mux;
struct fst_mux *fst_mux_init(const char *drv_iface_name);
int fst_mux_start(struct fst_mux *ctx);
int fst_mux_register_iface(struct fst_mux *ctx, const char *iface_name,
u8 priority);
int fst_mux_add_map_entry(struct fst_mux *ctx, const u8 *da,
const char *iface_name);
int fst_mux_del_map_entry(struct fst_mux *ctx, const u8 *da);
void fst_mux_unregister_iface(struct fst_mux *ctx, const char *iface_name);
void fst_mux_stop(struct fst_mux *ctx);
void fst_mux_cleanup(struct fst_mux *ctx);
#endif /* __FST_MUX_H__ */

View File

@@ -0,0 +1,482 @@
/*
* FST bonding + TC based mux implementation
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/list.h"
#include "common/defs.h"
#include "fst_mux.h"
#include "fst_tc.h"
#include "fst_cfgmgr.h"
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_bonding.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#define FST_MGR_COMPONENT "MUX"
#include "fst_manager.h"
#define BOND_ABI_VERSION 2
#define BOND_SYSFS_ROOT "/sys/class/net"
#define BOND_SYSFS_QUEUEID "bonding/queue_id"
struct fst_mux_iface
{
char ifname[IFNAMSIZ + 1];
u8 priority;
int queue_id;
struct dl_list filters;
struct dl_list lentry;
};
struct fst_mux_filter
{
u8 da[ETH_ALEN];
struct fst_tc_filter_handle filter_handle;
struct fst_mux_iface *iface;
struct dl_list lentry;
};
struct fst_mux
{
char bond_ifname[IFNAMSIZ + 1];
struct dl_list ifaces;
int skfd;
int queue_id;
struct fst_tc *tc;
};
struct fst_mux_iface * _drv_get_iface_by_name(struct fst_mux *ctx,
const char *ifname)
{
struct fst_mux_iface *i;
dl_list_for_each(i, &ctx->ifaces, struct fst_mux_iface, lentry) {
if (!os_strcmp(i->ifname, ifname))
return i;
}
return NULL;
}
struct fst_mux_filter *_drv_get_filter_by_da(struct fst_mux *ctx, const u8 *da)
{
struct fst_mux_iface *i;
dl_list_for_each(i, &ctx->ifaces, struct fst_mux_iface, lentry) {
struct fst_mux_filter *f;
dl_list_for_each(f, &i->filters, struct fst_mux_filter, lentry) {
if (os_memcmp(f->da, da, ETH_ALEN) == 0) {
return f;
}
}
}
return NULL;
}
static int
__mux_bond_get_info(struct fst_mux *ctx)
{
struct ifreq ifr;
struct ethtool_drvinfo info;
char *endptr;
int abi_ver;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ctx->bond_ifname, IFNAMSIZ);
ifr.ifr_data = (caddr_t)&info;
info.cmd = ETHTOOL_GDRVINFO;
os_strlcpy(info.driver, "ifenslave", 32);
os_snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
if (ioctl(ctx->skfd, SIOCETHTOOL, &ifr) < 0) {
fst_mgr_printf(MSG_ERROR, "SIOCETHTOOL failed on %s: %s",
ctx->bond_ifname, strerror(errno));
return -1;
}
abi_ver = strtoul(info.fw_version, &endptr, 0);
if (*endptr) {
fst_mgr_printf(MSG_ERROR, "Invalid ABI version arrived from %s",
ctx->bond_ifname);
return -1;
}
fst_mgr_printf(MSG_DEBUG, "ABI ver is %d", abi_ver);
return 0;
}
static int _mux_bond_assign_queue_id(struct fst_mux *ctx,
const char *slave_ifname, int queue_id)
{
FILE *f;
char fname[256];
snprintf(fname, sizeof(fname), BOND_SYSFS_ROOT "/%s/" BOND_SYSFS_QUEUEID,
ctx->bond_ifname);
f = fopen(fname, "w");
if (!f) {
fst_mgr_printf(MSG_ERROR, "cannot open queu_id file: %s",
strerror(errno));
return -1;
}
fprintf(f, "%s:%d", slave_ifname, queue_id);
fclose(f);
return 0;
}
static int _mux_bond_connect(struct fst_mux *ctx)
{
short ifru_flags;
if ((ctx->skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fst_mgr_printf(MSG_ERROR, "cannot open socket: %s",
strerror(errno));
goto fail;
}
if (__mux_bond_get_info(ctx)) {
fst_mgr_printf(MSG_ERROR, "cannot get bond info");
goto fail;
}
if (get_iface_flags(ctx->bond_ifname, &ifru_flags)) {
fst_mgr_printf(MSG_ERROR, "cannot get bond flags");
goto fail;
}
if (!(ifru_flags & IFF_MASTER)) {
fst_mgr_printf(MSG_ERROR, "%s isn't a master",
ctx->bond_ifname);
goto fail;
}
if (!(ifru_flags & IFF_UP)) {
fst_mgr_printf(MSG_ERROR, "%s is down",
ctx->bond_ifname);
goto fail;
}
return 0;
fail:
return -1;
}
static int _drv_del_filter(struct fst_mux *ctx, struct fst_mux_filter *filter,
Boolean force_removal)
{
if (!fst_tc_del_l2da_filter(ctx->tc, &filter->filter_handle))
fst_mgr_printf(MSG_DEBUG,
"TC filter deleted for [" MACSTR "]",
MAC2STR(filter->da));
else {
fst_mgr_printf(MSG_ERROR,
"Cannot delete TC filter for [" MACSTR "]",
MAC2STR(filter->da));
if (!force_removal)
return -1;
}
dl_list_del(&filter->lentry);
/* STA can only have 1 peer (AP), so it should have no filters
* installed after we removed the previous one */
WPA_ASSERT(!fst_is_supplicant() ||
dl_list_empty(&filter->iface->filters));
os_free(filter);
return 0;
}
static void _drv_purge_iface_filters(struct fst_mux *ctx,
struct fst_mux_iface *iface)
{
while (1) {
struct fst_mux_filter *filter =
dl_list_first(&iface->filters, struct fst_mux_filter, lentry);
if (!filter)
break;
_drv_del_filter(ctx, filter, TRUE);
}
}
static void _drv_purge_filters(struct fst_mux *ctx)
{
struct fst_mux_iface *iface;
dl_list_for_each(iface, &ctx->ifaces, struct fst_mux_iface, lentry)
_drv_purge_iface_filters(ctx, iface);
}
void _drv_del_iface(struct fst_mux *ctx, struct fst_mux_iface *iface)
{
dl_list_del(&iface->lentry);
_drv_purge_iface_filters(ctx, iface);
os_free(iface);
}
static void _drv_bond_disconnect(struct fst_mux *ctx)
{
close(ctx->skfd);
ctx->skfd = -1;
}
struct fst_mux *fst_mux_init(const char *group_name)
{
struct fst_mux *ctx = NULL;
int len;
char buf[80];
len = fst_cfgmgr_get_mux_type(group_name, buf, sizeof(buf)-1);
if (len) {
if (os_strcmp(buf, "bonding")) {
fst_mgr_printf(MSG_ERROR, "Unsupported mux type: %s", buf);
goto fail_mux_type;
}
}
ctx = os_zalloc(sizeof(*ctx));
if (!ctx) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate driver for %s",
group_name);
goto fail_no_ctx;
}
len = fst_cfgmgr_get_mux_ifname(group_name, ctx->bond_ifname,
sizeof(ctx->bond_ifname)-1);
if (len == 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux ifname");
goto fail_mux_name;
}
dl_list_init(&ctx->ifaces);
ctx->skfd = -1;
ctx->queue_id = 0;
if (_mux_bond_connect(ctx)) {
fst_mgr_printf(MSG_ERROR, "Cannot connect to bond#%s",
ctx->bond_ifname);
goto fail_connect;
}
ctx->tc = fst_tc_create(fst_is_supplicant());
if (!ctx->tc) {
fst_mgr_printf(MSG_ERROR, "Cannot create FST TC bond#%s",
ctx->bond_ifname);
goto fail_tc_create;
}
fst_mgr_printf(MSG_DEBUG, "driver initialized for %s",
ctx->bond_ifname);
return ctx;
fail_tc_create:
_drv_bond_disconnect(ctx);
fail_connect:
fail_mux_name:
os_free(ctx);
fail_no_ctx:
fail_mux_type:
return NULL;
}
int fst_mux_start(struct fst_mux *ctx)
{
struct fst_mux_iface *i;
dl_list_for_each(i, &ctx->ifaces, struct fst_mux_iface, lentry) {
i->queue_id = ++ctx->queue_id;
if (_mux_bond_assign_queue_id(ctx, i->ifname, i->queue_id)) {
fst_mgr_printf(MSG_ERROR, "Cannot assign queue_id#%d for %s",
i->queue_id, i->ifname);
goto fail;
}
}
if (fst_tc_start(ctx->tc, ctx->bond_ifname) != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot start FST TC bond#%s",
ctx->bond_ifname);
goto fail;
}
fst_mgr_printf(MSG_DEBUG, "%s initialized",
ctx->bond_ifname);
return 0;
fail:
dl_list_for_each(i, &ctx->ifaces, struct fst_mux_iface, lentry)
_mux_bond_assign_queue_id(ctx, i->ifname, 0);
return -1;
}
int fst_mux_register_iface(struct fst_mux *ctx, const char *iface_name,
u8 priority)
{
struct fst_mux_iface *iface;
iface = _drv_get_iface_by_name(ctx, iface_name);
if (iface) {
fst_mgr_printf(MSG_ERROR, "Slave (%s) already regirestred with bond#%s",
iface_name, ctx->bond_ifname);
goto fail;
}
iface = os_zalloc(sizeof(*iface));
if (!iface) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate object for %s",
iface_name);
goto fail;
}
if (fst_tc_register_iface(ctx->tc, iface_name)) {
fst_mgr_printf(MSG_ERROR, "Cannot register TC for %s",
iface_name);
goto fail_tc_register;
}
iface->priority = priority;
dl_list_init(&iface->filters);
os_strlcpy(iface->ifname, iface_name, sizeof(iface->ifname));
dl_list_add_tail(&ctx->ifaces, &iface->lentry);
fst_mgr_printf(MSG_DEBUG, "interface %s registered with %s",
iface_name, ctx->bond_ifname);
return 0;
fail_tc_register:
os_free(iface);
fail:
return -1;
}
int fst_mux_add_map_entry(struct fst_mux *ctx, const u8 *da,
const char *iface_name)
{
struct fst_mux_iface *iface;
struct fst_mux_filter *filter;
iface = _drv_get_iface_by_name(ctx, iface_name);
if (!iface) {
fst_mgr_printf(MSG_ERROR, "Cannot find interface %s", iface_name);
return -1;
}
fst_mux_del_map_entry(ctx, da);
filter = os_zalloc(sizeof(*filter));
if (!filter) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate filter "
"for [" MACSTR ",%s]",
MAC2STR(da), iface_name);
return -1;
}
if (fst_tc_add_l2da_filter(ctx->tc, da, iface->queue_id, iface_name,
&filter->filter_handle)) {
fst_mgr_printf(MSG_ERROR, "Cannot add TC filter for [" MACSTR ",%s]",
MAC2STR(da), iface_name);
os_free(filter);
return -1;
}
os_memcpy(filter->da, da, ETH_ALEN);
filter->iface = iface;
dl_list_add_tail(&iface->filters, &filter->lentry);
fst_mgr_printf(MSG_DEBUG, "TC filter added for [" MACSTR ",%s]",
MAC2STR(da), iface_name);
return 0;
}
int fst_mux_del_map_entry(struct fst_mux *ctx, const u8 *da)
{
struct fst_mux_filter *filter;
filter = _drv_get_filter_by_da(ctx, da);
if (!filter) {
fst_mgr_printf(MSG_ERROR, "Cannot find TC filter for [" MACSTR "]",
MAC2STR(da));
return -1;
}
return _drv_del_filter(ctx, filter, FALSE);
}
void fst_mux_unregister_iface(struct fst_mux *ctx, const char *iface_name)
{
struct fst_mux_iface *iface;
fst_tc_unregister_iface(ctx->tc, iface_name);
iface = _drv_get_iface_by_name(ctx, iface_name);
if (iface) {
_drv_del_iface(ctx, iface);
fst_mgr_printf(MSG_DEBUG, "interface %s unregistered with %s",
iface_name, ctx->bond_ifname);
}
}
void fst_mux_stop(struct fst_mux *ctx)
{
struct fst_mux_iface *i;
_drv_purge_filters(ctx);
fst_tc_stop(ctx->tc);
dl_list_for_each(i, &ctx->ifaces, struct fst_mux_iface, lentry) {
_mux_bond_assign_queue_id(ctx, i->ifname, 0);
}
ctx->queue_id = 0;
}
void fst_mux_cleanup(struct fst_mux *ctx)
{
while (TRUE) {
struct fst_mux_iface *iface =
dl_list_first(&ctx->ifaces, struct fst_mux_iface, lentry);
if (!iface)
break;
_drv_del_iface(ctx, iface);
}
fst_tc_delete(ctx->tc);
_drv_bond_disconnect(ctx);
fst_mgr_printf(MSG_DEBUG, "driver cleaned up for %s",
ctx->bond_ifname);
os_free(ctx);
}

View File

@@ -0,0 +1,359 @@
/*
* FST L2DA + NETLINK based mux implementation
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/socket.h>
#include <netlink/attr.h>
#include <netlink/msg.h>
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/list.h"
#include <linux/if_bonding_genl.h>
#include "common/defs.h"
#include "fst_mux.h"
#include "fst_cfgmgr.h"
#define FST_MGR_COMPONENT "MUX"
#include "fst_manager.h"
struct fst_mux
{
char bond_ifname[IFNAMSIZ + 1];
char *ap_default_ifname;
struct nl_sock *nl;
int fam_id;
};
#define BOND_L2DA_STA_OPTS (BOND_L2DA_OPT_DEDUP_RX | \
BOND_L2DA_OPT_REPLACE_MAC | \
BOND_L2DA_OPT_AUTO_ARP_ANNOUNCE )
#define BOND_L2DA_AP_OPTS (BOND_L2DA_OPT_DUP_MC_TX | \
BOND_L2DA_OPT_FORWARD_RX)
static struct nl_msg * _init_genl_msg(struct fst_mux *ctx, int cmd)
{
struct nl_msg *msg;
void *hdr;
int res;
msg = nlmsg_alloc();
if(msg == NULL) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate nlmsg");
goto fail_nlmsg;
}
hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->fam_id,
0, NLM_F_REQUEST | NLM_F_ACK, cmd, BOND_GENL_VERSION);
if (hdr == NULL) {
fst_mgr_printf(MSG_ERROR, "genlmsg_put failed");
goto fail_nlmsg_put;
}
res = nla_put_string(msg, BOND_GENL_ATTR_BOND_NAME, ctx->bond_ifname);
if (res != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot put bond: %s", nl_geterror(res));
goto fail_nlmsg_put;
}
fst_mgr_printf(MSG_DEBUG, " _init_genl_msg created msg for %d cmd", cmd);
return msg;
fail_nlmsg_put:
nlmsg_free(msg);
fail_nlmsg:
return NULL;
}
static int _send_and_free_genl_msg(struct fst_mux *ctx, struct nl_msg *msg)
{
int res;
res = nl_send_auto(ctx->nl, msg);
nlmsg_free(msg);
if (res < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot nl_send: %s", nl_geterror(res));
return -1;
}
return 0;
}
static int _send_genl_reset_map_msg(struct fst_mux *ctx)
{
struct nl_msg *msg;
int res;
msg = _init_genl_msg(ctx, BOND_GENL_CMD_L2DA_RESET_MAP);
if (msg == NULL)
return -1;
res = _send_and_free_genl_msg(ctx, msg);
if (!res)
fst_mgr_printf(MSG_INFO, "L2DA map reset");
else
fst_mgr_printf(MSG_ERROR, "Cannot reset L2DA map");
return res;
}
static int _send_genl_set_opts_msg(struct fst_mux *ctx, u32 opts)
{
struct nl_msg *msg;
int res;
msg = _init_genl_msg(ctx, BOND_GENL_CMD_L2DA_SET_OPTS);
if (msg == NULL)
return -1;
res = nla_put_u32(msg, BOND_GENL_ATTR_L2DA_OPTS, opts);
if (res != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot put opts: %s",
nl_geterror(res));
nlmsg_free(msg);
return -1;
}
res = _send_and_free_genl_msg(ctx, msg);
if (!res)
fst_mgr_printf(MSG_INFO, "L2DA opts set to 0x%08x", opts);
else
fst_mgr_printf(MSG_ERROR, "Cannot set L2DA opts");
return res;
}
static int _send_genl_set_def_slave_msg(struct fst_mux *ctx, const char *ifname)
{
struct nl_msg *msg;
int res;
msg = _init_genl_msg(ctx, BOND_GENL_CMD_L2DA_SET_DEFAULT);
if (msg == NULL)
return -1;
res = nla_put_string(msg, BOND_GENL_ATTR_SLAVE_NAME, ifname);
if (res != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot put slave: %s",
nl_geterror(res));
nlmsg_free(msg);
return -1;
}
res = _send_and_free_genl_msg(ctx, msg);
if (!res)
fst_mgr_printf(MSG_INFO, "L2DA default slave set to %s",
ifname);
else
fst_mgr_printf(MSG_ERROR, "Cannot set L2DA default slave");
return res;
}
static int _send_genl_set_change_map_msg(struct fst_mux *ctx, const u8 *da,
const char *ifname)
{
struct nl_msg *msg;
int res;
res = ifname ? BOND_GENL_CMD_L2DA_ADD_MAP_ENTRY :
BOND_GENL_CMD_L2DA_DEL_MAP_ENTRY;
msg = _init_genl_msg(ctx, res);
if (msg == NULL)
return -1;
res = nla_put(msg, BOND_GENL_ATTR_MAC, ETH_ALEN, da);
if (res != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot put address: %s", nl_geterror(res));
goto fail_nlmsg_put;
}
if (ifname) {
res = nla_put_string(msg, BOND_GENL_ATTR_SLAVE_NAME, ifname);
if (res != 0) {
fst_mgr_printf(MSG_ERROR, "Cannot put slave: %s",
nl_geterror(res));
goto fail_nlmsg_put;
}
}
res = _send_and_free_genl_msg(ctx, msg);
if (!res)
fst_mgr_printf(MSG_INFO, "L2DA map entry changed ["MACSTR",%s]",
MAC2STR(da), ifname ? ifname : "NULL");
else
fst_mgr_printf(MSG_ERROR,
"Cannot change L2DA map entry ["MACSTR", %s]",
MAC2STR(da), ifname ? ifname : "NULL");
return res;
fail_nlmsg_put:
nlmsg_free(msg);
return -1;
}
struct fst_mux *fst_mux_init(const char *group_name)
{
struct fst_mux *ctx = NULL;
int len;
char buf[80];
char ifname[IFNAMSIZ + 1];
len = fst_cfgmgr_get_mux_type(group_name, buf, sizeof(buf)-1);
if (len) {
if (os_strcmp(buf, "bonding_l2da")) {
fst_mgr_printf(MSG_ERROR, "Unsupported mux type: %s", buf);
return NULL;
}
}
ctx = os_zalloc(sizeof(*ctx));
if (!ctx) {
fst_mgr_printf(MSG_ERROR, "Cannot allocate driver for %s",
group_name);
return NULL;
}
len = fst_cfgmgr_get_mux_ifname(group_name, ctx->bond_ifname,
sizeof(ctx->bond_ifname)-1);
if (len == 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux ifname");
goto fail_mux_name;
}
if (!fst_is_supplicant() &&
fst_cfgmgr_get_l2da_ap_default_ifname(group_name, ifname,
sizeof(ifname)-1) > 0) {
ctx->ap_default_ifname = os_strdup(ifname);
if (!ctx->ap_default_ifname) {
fst_mgr_printf(MSG_ERROR, "Cannot dup ap default ifname");
goto fail_ap_default_name;
}
}
ctx->nl = nl_socket_alloc();
if (!ctx->nl) {
fst_mgr_printf(MSG_ERROR, "Cannot alloc nl socket");
goto fail_nl_socket;
}
if (genl_connect(ctx->nl)) {
fst_mgr_printf(MSG_ERROR, "genl_connect failed");
goto fail_nl_connect;
}
nl_socket_disable_seq_check(ctx->nl);
ctx->fam_id = genl_ctrl_resolve(ctx->nl, BOND_GENL_NAME);
if (ctx->fam_id < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get nl family id");
goto fail_nl_famid;
}
fst_mgr_printf(MSG_DEBUG, "mux_l2da initialized for %s",
ctx->bond_ifname);
return ctx;
fail_nl_famid:
fail_nl_connect:
nl_socket_free(ctx->nl);
fail_nl_socket:
os_free(ctx->ap_default_ifname);
fail_ap_default_name:
fail_mux_name:
os_free(ctx);
return NULL;
}
int fst_mux_start(struct fst_mux *ctx)
{
u32 opts;
if(_send_genl_reset_map_msg(ctx) != 0) {
fst_mgr_printf(MSG_ERROR, "Error starting mux: reset map");
return -1;
}
opts = fst_is_supplicant() ? BOND_L2DA_STA_OPTS : BOND_L2DA_AP_OPTS;
if (_send_genl_set_opts_msg(ctx, opts)) {
fst_mgr_printf(MSG_ERROR, "Error starting mux: set opts");
return -1;
}
if (!fst_is_supplicant() && ctx->ap_default_ifname &&
_send_genl_set_def_slave_msg(ctx, ctx->ap_default_ifname)) {
fst_mgr_printf(MSG_ERROR, "Error starting mux: set ap default iface");
return -1;
}
return 0;
}
int fst_mux_add_map_entry(struct fst_mux *ctx, const u8 *da,
const char *iface_name)
{
return fst_is_supplicant() ?
_send_genl_set_def_slave_msg(ctx, iface_name) :
_send_genl_set_change_map_msg(ctx, da, iface_name);
}
int fst_mux_del_map_entry(struct fst_mux *ctx, const u8 *da)
{
/* "No need to del map entry for STA as we use default slave */
return fst_is_supplicant() ?
0 : _send_genl_set_change_map_msg(ctx, da, NULL);
}
int fst_mux_register_iface(struct fst_mux *ctx, const char *iface_name,
u8 priority)
{
return 0; /* Left for mux API compatibility */
}
void fst_mux_unregister_iface(struct fst_mux *ctx, const char *iface_name)
{
/* Left for mux API compatibility */
}
void fst_mux_stop(struct fst_mux *ctx)
{
if(_send_genl_reset_map_msg(ctx) != 0)
fst_mgr_printf(MSG_WARNING, "Error stopping mux");
}
void fst_mux_cleanup(struct fst_mux *ctx)
{
nl_socket_free(ctx->nl);
os_free(ctx->ap_default_ifname);
os_free(ctx);
}

View File

@@ -0,0 +1,808 @@
/*
* FST Manager: Rate Upgrade
*
* Copyright (c) 2015-2016, 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "utils/list.h"
#include "fst_rateupg.h"
#include "fst_tpoll.h"
#include "fst_capconfigstore.h"
#define FST_MGR_COMPONENT "RATEUPG"
#include "fst_manager.h"
#include "common/ieee802_11_defs.h"
#define FST_MAX_MCS 15
#define FST_SIGNAL_MONITOR_DEFAULT_RSSI -55
#define FST_SIGNAL_MONITOR_DEFAULT_HYST 5
static const char FST_CONFIG_SENSITIVITY_LEVEL_KEY_NAME[] = "fst.config.sensitivity.level";
#define FST_CONFIG_SENSITIVITY_LEVEL "1" /* Medium */
static const char FST_CONFIG_ENTRY_MCS_KEY_NAME[] = "fst.config.entry.mcs";
#define FST_CONFIG_ENTRY_MCS "9"
static const char FST_CONFIG_EXIT_MCS_KEY_NAME[] = "fst.config.exit.mcs";
#define FST_CONFIG_EXIT_MCS "3"
enum wmi_fst_switch_sensitivity_level {
WMI_FST_SWITCH_SENSITIVITY_LOW = 0x00,
WMI_FST_SWITCH_SENSITIVITY_MED = 0x01,
WMI_FST_SWITCH_SENSITIVITY_HIGH = 0x02,
};
struct rate_upgrade_mac {
u8 addr[ETH_ALEN];
struct dl_list lentry;
};
struct rate_upgrade_group {
char *groupname;
char *master;
char *acl_fname;
struct fst_iface_info *slaves;
int slave_cnt;
struct dl_list acl_macs;
Boolean is_duped;
struct dl_list lentry;
};
struct rate_upgrade_manager {
struct fst_ini_config *iniconf;
struct dl_list groups;
/* FST config from xml */
int sensitivity_level;
int entryMCS;
int exitMCS;
int tpoll_interval;
int tpoll_alpha;
};
static struct rate_upgrade_manager g_rateupg_mgr;
static int g_rateupg_mgr_initialized = 0;
static struct rate_upgrade_mac *find_rate_upgrade_mac(
struct rate_upgrade_group *g, const u8 *addr)
{
struct rate_upgrade_mac *p;
if (!addr)
return dl_list_first(&g->acl_macs, struct rate_upgrade_mac, lentry);
dl_list_for_each(p, &g->acl_macs, struct rate_upgrade_mac, lentry)
if (!os_memcmp(p->addr, addr, ETH_ALEN))
return p;
return NULL;
}
static struct rate_upgrade_mac *add_rate_upgrade_mac(
struct rate_upgrade_group *g, const u8 *addr)
{
struct rate_upgrade_mac *p = os_malloc(sizeof(*p));
if (p) {
os_memcpy(p->addr, addr, ETH_ALEN);
dl_list_add_tail(&g->acl_macs, &p->lentry);
}
return p;
}
static void del_rate_upgrade_mac(struct rate_upgrade_mac *p)
{
dl_list_del(&p->lentry);
os_free(p);
}
static int update_acl_file(struct rate_upgrade_group *g)
{
struct rate_upgrade_mac *p;
int res = -1;
FILE *f;
if (!g->acl_fname)
return 0;
f = fopen(g->acl_fname, "w");
if (!f) {
fst_mgr_printf(MSG_ERROR, "group %s: cannot open acl file: %s",
g->groupname, g->acl_fname);
goto error_file;
}
dl_list_for_each(p, &g->acl_macs, struct rate_upgrade_mac, lentry)
if (fprintf(f, MACSTR "\n", MAC2STR(p->addr)) <= 0) {
fst_mgr_printf(MSG_ERROR,
"group %s: cannot fill acl file: %s",
g->groupname, g->acl_fname);
goto error_fprintf;
}
res = 0;
error_fprintf:
fclose(f);
error_file:
return res;
}
static struct rate_upgrade_group *find_rate_upgrade_group(const char *name)
{
struct rate_upgrade_group *g;
dl_list_for_each(g, &g_rateupg_mgr.groups, struct rate_upgrade_group, lentry) {
if(!strncmp(g->groupname, name, strlen(name)))
return g;
}
return NULL;
}
static void deinit_rate_upgrade_group(struct rate_upgrade_group *g)
{
free(g->slaves);
free(g->master);
free(g->groupname);
free(g->acl_fname);
dl_list_del(&g->lentry);
free(g);
}
int fst_rate_upgrade_init(struct fst_ini_config *h)
{
int res;
char buf[64] = { '\0' };
os_memset(&g_rateupg_mgr, 0, sizeof(g_rateupg_mgr));
dl_list_init(&g_rateupg_mgr.groups);
g_rateupg_mgr.iniconf = h;
fst_get_config_string(FST_CONFIG_SENSITIVITY_LEVEL_KEY_NAME,
FST_CONFIG_SENSITIVITY_LEVEL, buf, sizeof(buf));
g_rateupg_mgr.sensitivity_level = strtoul(buf, NULL, 0);
switch (g_rateupg_mgr.sensitivity_level) {
case WMI_FST_SWITCH_SENSITIVITY_LOW:
g_rateupg_mgr.tpoll_interval = 200;
g_rateupg_mgr.tpoll_alpha = 20;
break;
case WMI_FST_SWITCH_SENSITIVITY_MED:
g_rateupg_mgr.tpoll_interval = 100;
g_rateupg_mgr.tpoll_alpha = 40;
break;
case WMI_FST_SWITCH_SENSITIVITY_HIGH:
g_rateupg_mgr.tpoll_interval = 50;
g_rateupg_mgr.tpoll_alpha = 50;
break;
default:
return -1;
}
fst_get_config_string(FST_CONFIG_ENTRY_MCS_KEY_NAME,
FST_CONFIG_ENTRY_MCS, buf, sizeof(buf));
g_rateupg_mgr.entryMCS = strtoul(buf, NULL, 0);
if (g_rateupg_mgr.entryMCS < 0 || g_rateupg_mgr.entryMCS > FST_MAX_MCS)
return -1;
fst_get_config_string(FST_CONFIG_EXIT_MCS_KEY_NAME,
FST_CONFIG_EXIT_MCS, buf, sizeof(buf));
g_rateupg_mgr.exitMCS = strtoul(buf, NULL, 0);
if (g_rateupg_mgr.exitMCS < 0 || g_rateupg_mgr.exitMCS > FST_MAX_MCS)
return -1;
if (g_rateupg_mgr.entryMCS <= g_rateupg_mgr.exitMCS)
return -1;
fst_mgr_printf(MSG_INFO, "sensitivity_level %d entry/exit MCS %d/%d",
g_rateupg_mgr.sensitivity_level, g_rateupg_mgr.entryMCS, g_rateupg_mgr.exitMCS);
res = fst_tpoll_init(g_rateupg_mgr.tpoll_interval, g_rateupg_mgr.tpoll_alpha);
if (res)
return res;
g_rateupg_mgr_initialized = 1;
return 0;
}
void fst_rate_upgrade_deinit()
{
if (g_rateupg_mgr_initialized) {
while (!dl_list_empty(&g_rateupg_mgr.groups)) {
struct rate_upgrade_group *g = dl_list_first(&g_rateupg_mgr.groups,
struct rate_upgrade_group, lentry);
deinit_rate_upgrade_group(g);
}
g_rateupg_mgr_initialized = 0;
}
fst_tpoll_deinit();
}
int fst_rate_upgrade_add_group(const struct fst_group_info *group)
{
struct rate_upgrade_group *g;
struct fst_iface_info *ifaces;
int i;
char *master = NULL;
char *acl_fname = NULL;
char ctrl_iface_dir[256];
int ctrl_iface_dir_len;
if (find_rate_upgrade_group(group->id)) {
fst_mgr_printf(MSG_WARNING, "Group %s already added", group->id);
return 0;
}
master = fst_ini_config_get_rate_upgrade_master(
g_rateupg_mgr.iniconf, group->id);
if (!master)
return 0;
if (!fst_is_supplicant()) {
acl_fname = fst_ini_config_get_rate_upgrade_acl_fname(
g_rateupg_mgr.iniconf, group->id);
if (acl_fname != NULL)
fst_mgr_printf(MSG_INFO, "Using ACL file %s", acl_fname);
}
g = malloc(sizeof(struct rate_upgrade_group));
if (!g) {
fst_mgr_printf(MSG_ERROR, "Cannot alloc group %s",
group->id);
goto error_group;
}
memset(g, 0, sizeof(struct rate_upgrade_group));
g->master = master;
g->groupname = strdup(group->id);
if (g->groupname == NULL) {
fst_mgr_printf(MSG_ERROR, "Cannot alloc groupname %s",
group->id);
goto error_groupname;
}
g->slave_cnt = fst_ini_config_get_group_slave_ifaces(
g_rateupg_mgr.iniconf, group, master, &ifaces);
if (g->slave_cnt < 0) {
fst_mgr_printf(MSG_ERROR, "Cannot add group %s", group->id);
goto error_get_slave;
}
else if (g->slave_cnt == 0) {
fst_mgr_printf(MSG_ERROR,
"No slave ifaces found in group %s", group->id);
goto error_get_slave;
}
g->slaves = ifaces;
dl_list_init(&g->acl_macs);
g->acl_fname = acl_fname;
if (update_acl_file(g)) {
fst_mgr_printf(MSG_ERROR, "Cannot update ACL file");
goto error_acl_file;
}
ctrl_iface_dir_len = fst_ini_config_get_slave_ctrl_interface(
g_rateupg_mgr.iniconf, ctrl_iface_dir, sizeof(ctrl_iface_dir));
for (i = 0; i < g->slave_cnt; i++) {
if (ifaces[i].manual_enslave)
continue;
if (fst_add_iface(master, &ifaces[i], g->acl_fname,
(ctrl_iface_dir_len > 0) ? ctrl_iface_dir : NULL)) {
fst_mgr_printf(MSG_ERROR,
"Cannot add slave interface %s", ifaces[i].name);
goto error_add;
}
}
dl_list_add_tail(&g_rateupg_mgr.groups, &g->lentry);
return 0;
error_add:
while(i-- > 0)
fst_del_iface(&ifaces[i]);
error_acl_file:
free(ifaces);
error_get_slave:
free(g->groupname);
error_groupname:
free(g);
error_group:
free(acl_fname);
free(master);
return -1;
}
int fst_rate_upgrade_del_group(const struct fst_group_info *group)
{
struct rate_upgrade_group *g;
int i;
g = find_rate_upgrade_group(group->id);
if (g == NULL) {
fst_mgr_printf(MSG_ERROR, "No group exists %s", group->id);
return -1;
}
for (i = 0; i < g->slave_cnt; i++) {
if (fst_del_iface(&g->slaves[i])) {
fst_mgr_printf(MSG_ERROR, "Cannot delete iface %s",
g->slaves[i].name);
}
}
deinit_rate_upgrade_group(g);
return 0;
}
static int fst_dup_connection_sta(struct rate_upgrade_group *g,
const char *iface, const u8* addr)
{
int i;
char *str_mbies = NULL;
int str_mbies_size;
int mbies_size;
u8 *mbies = NULL, *mbies_iter;
str_mbies_size = fst_get_peer_mbies(iface, addr, &str_mbies);
if (str_mbies_size < 2 || str_mbies_size & 1) {
fst_mgr_printf(MSG_INFO, "invalid mbies size %d",
str_mbies_size);
for (i = 0; i < g->slave_cnt; i++) {
if (fst_dup_connection(&g->slaves[i], g->master, addr, 0,
g->acl_fname)) {
fst_mgr_printf(MSG_ERROR, "Cannot connect iface %s",
g->slaves[i].name);
goto error_connect;
}
}
os_free(str_mbies);
return 0;
}
mbies_size = str_mbies_size / 2;
mbies = os_malloc(mbies_size);
if (!mbies) {
fst_mgr_printf(MSG_ERROR, "mbies allocation failed");
goto error_mbie;
}
if (hexstr2bin(str_mbies, mbies, mbies_size)) {
fst_mgr_printf(MSG_ERROR, "failed converting hex mbie to bin");
goto error_mbie;
}
/* for each slave duplicate the addresses from all bands */
for (i = 0; i < g->slave_cnt; i++) {
mbies_iter = mbies;
while (mbies_size >= 2) {
struct multi_band_ie *mbie = (struct multi_band_ie *) mbies_iter;
const u8 *addr_on_other_band;
u32 freq = 0;
if (mbie->eid != WLAN_EID_MULTI_BAND ||
(size_t) 2 + mbie->len < sizeof(*mbie))
break;
addr_on_other_band = fst_mgr_get_addr_from_mbie(mbie);
if (!addr_on_other_band)
continue;
if (mbie->band_id == MB_BAND_ID_WIFI_60GHZ)
freq = 56160 + mbie->chan * 2160;
if (fst_dup_connection(&g->slaves[i], g->master,
addr_on_other_band, freq,
g->acl_fname))
goto error_connect;
mbies_iter += mbie->len + 2;
mbies_size -= mbie->len + 2;
}
}
g->is_duped = TRUE;
os_free(str_mbies);
os_free(mbies);
return 0;
error_connect:
while (i-- > 0)
fst_dedup_connection(&g->slaves[i], g->acl_fname);
error_mbie:
os_free(str_mbies);
os_free(mbies);
return -1;
}
static int fst_dup_connection_ap(struct rate_upgrade_group *g,
const u8* addr)
{
int i;
for (i = 0; i < g->slave_cnt; i++) {
if (fst_dup_connection(&g->slaves[i], g->master, addr, 0,
g->acl_fname)) {
fst_mgr_printf(MSG_ERROR, "Cannot connect iface %s",
g->slaves[i].name);
goto error_connect;
}
}
g->is_duped = TRUE;
return 0;
error_connect:
while (i-- > 0)
fst_dedup_connection(&g->slaves[i], g->acl_fname);
return -1;
}
static int
fst_rate_upgrade_config_device(struct rate_upgrade_group *g, const u8 *peer, int enabled)
{
int res = 0, i;
for (i = 0; i < g->slave_cnt; i++) {
char fname[128];
FILE *f;
if (snprintf(fname, sizeof(fname), "/sys/class/net/%s/device/wil6210/fst_config",
g->slaves[i].name) < 0) {
res = -1;
goto out;
}
f = fopen(fname, "w");
if (!f) {
fst_mgr_printf(MSG_ERROR, "failed to open: %s", fname);
res = -1;
goto out;
}
/* <ap_bssid> <enabled> <entry_mcs> <exit_mcs> <sensitivity_level> */
if (fprintf(f, MACSTR " %d %d %d %d\n", MAC2STR(peer), enabled, g_rateupg_mgr.entryMCS,
g_rateupg_mgr.exitMCS, g_rateupg_mgr.sensitivity_level) < 0) {
res = -1;
}
fclose(f);
}
out:
if (res < 0)
fst_mgr_printf(MSG_WARNING, "failed to set fst config %s",
enabled ? "On" : "Off");
else
fst_mgr_printf(MSG_INFO, "fst config %s for peer " MACSTR,
enabled ? "enabled" : "disabled",
MAC2STR(peer));
return res;
}
int fst_rate_upgrade_on_connect(const struct fst_group_info *group,
const char *iface, const u8* addr)
{
int res;
struct rate_upgrade_group *g;
struct rate_upgrade_mac *p;
g = find_rate_upgrade_group(group->id);
if (!g)
return 0;
if (os_strcmp(iface, g->master)) {
/* slave iface connect - trigger link monitoring */
res = fst_signal_monitor(iface, FST_SIGNAL_MONITOR_DEFAULT_RSSI, FST_SIGNAL_MONITOR_DEFAULT_HYST);
if (res) {
fst_mgr_printf(MSG_ERROR, "setting signal monitor failed on iface %s", iface);
/* continue without signal monitor */
}
return 0;
}
/* else - master iface connect */
if (find_rate_upgrade_mac(g, addr)) {
fst_mgr_printf(MSG_WARNING, "MAC " MACSTR
" is already connected", MAC2STR(addr));
return 0;
}
p = add_rate_upgrade_mac(g, addr);
if (!p) {
fst_mgr_printf(MSG_ERROR, "Cannot add MAC " MACSTR,
MAC2STR(addr));
return -1;
}
if (update_acl_file(g)) {
fst_mgr_printf(MSG_ERROR, "Cannot update ACL file");
goto error_acl_file;
}
if (fst_is_supplicant()) {
res = fst_rate_upgrade_config_device(g, addr, TRUE);
if (res)
goto error_acl_file;
/* for STA start traffic poller. dup connection takes place
* upon high tput on master.
*/
res = fst_tpoll_start(group);
} else {
res = fst_dup_connection_ap(g, addr);
}
if (!res)
return res;
error_acl_file:
fst_rate_upgrade_config_device(g, addr, FALSE);
fst_tpoll_stop();
del_rate_upgrade_mac(p);
return -1;
}
int fst_rate_upgrade_on_disconnect(const struct fst_group_info *group,
const char *iface, const u8* addr)
{
int i, res = 0;
struct rate_upgrade_group *g;
struct rate_upgrade_mac *p;
g = find_rate_upgrade_group(group->id);
if (!g)
return 0;
if (os_strcmp(iface, g->master)) {
/* slave iface disconnect - flush BSS cache to prevent supplicant
* from trying to reconnect due to cached scan result which leads
* to temp-disable situation.
*/
fst_ctrl_bss_flush(iface);
return 0;
}
/* else - master iface disconnect */
p = find_rate_upgrade_mac(g, addr);
if (!p) {
fst_mgr_printf(MSG_ERROR, "Cannot find master peer");
return -1;
}
fst_rate_upgrade_config_device(g, addr, FALSE);
fst_tpoll_stop();
del_rate_upgrade_mac(p);
if (update_acl_file(g)) {
fst_mgr_printf(MSG_ERROR, "Cannot update ACL file");
return -1;
}
for (i = 0; i < g->slave_cnt; i++) {
if (fst_dedup_connection(&g->slaves[i], g->acl_fname)) {
fst_mgr_printf(MSG_ERROR, "Cannot disconnect iface %s",
g->slaves[i].name);
res = -1;
}
}
g->is_duped = FALSE;
return res;
}
void fst_rate_upgrade_on_release(const struct fst_group_info *group,
const char *iface)
{
int i;
struct rate_upgrade_group *g = find_rate_upgrade_group(group->id);
if (!g)
return;
for (i = 0; i < g->slave_cnt; i++) {
if (os_strcmp(g->slaves[i].name, iface))
continue;
if (fst_dedup_connection(&g->slaves[i], g->acl_fname))
fst_mgr_printf(MSG_ERROR, "failed to disconnect iface %s", g->slaves[i].name);
break;
}
g->is_duped = FALSE;
}
void fst_rate_upgrade_on_switch_completed(const struct fst_group_info *group,
const char *old_iface, const char *new_iface, const u8* old_peer_addr)
{
struct rate_upgrade_group *g;
int ret;
fst_mgr_printf(MSG_INFO, "%s=>%s, old peer address " MACSTR,
old_iface, new_iface, MAC2STR(old_peer_addr));
if (fst_is_supplicant())
/* do nothing for STA mode */
return;
g = find_rate_upgrade_group(group->id);
if (!g) {
fst_mgr_printf(MSG_INFO, "%s is not a rate upgrade group", group->id);
return;
}
if (os_strcmp(old_iface, g->master) == 0) {
fst_mgr_printf(MSG_INFO, "switching from master, do nothing");
return;
}
/* old_iface is not master, disconnect from peer */
ret = fst_disconnect_peer(old_iface, old_peer_addr);
if (ret)
fst_mgr_printf(MSG_ERROR, "failed to disconnect peer");
}
void fst_rate_upgrade_rename_interface(const char *gname, const char *ifname, const char *newifname)
{
struct rate_upgrade_group *g;
int i;
g = find_rate_upgrade_group(gname);
if (!g) {
fst_mgr_printf(MSG_INFO, "%s is not a rate upgrade group", gname);
return;
}
if (!os_strcmp(g->master, ifname))
os_strlcpy(g->master, newifname, sizeof(g->master));
for (i = 0; i < g->slave_cnt; i++) {
if (!os_strcmp(g->slaves[i].name, ifname)) {
os_strlcpy(g->slaves[i].name, newifname, sizeof(g->slaves[i].name));
break;
}
}
}
void fst_rate_upgrade_high_traffic(const struct fst_group_info *group)
{
int res;
struct rate_upgrade_group *g;
struct rate_upgrade_mac *peer;
g = find_rate_upgrade_group(group->id);
if (!g)
return;
if (g->is_duped) {
fst_mgr_printf(MSG_INFO, "connection already duplicated, ignore");
return;
}
peer = find_rate_upgrade_mac(g, NULL);
if (peer == NULL) {
fst_mgr_printf(MSG_ERROR, "peer address not found");
return;
}
res = fst_dup_connection_sta(g, g->master, peer->addr);
if (res) {
fst_mgr_printf(MSG_ERROR, "dup connection failed, addr " MACSTR, MAC2STR(peer->addr));
}
}
void fst_rate_upgrade_low_traffic(const struct fst_group_info *group)
{
int i, res;
struct rate_upgrade_group *g;
struct rate_upgrade_mac *peer;
g = find_rate_upgrade_group(group->id);
if (!g)
return;
if (!g->is_duped) {
fst_mgr_printf(MSG_INFO, "connection not duplicated, ignore");
return;
}
peer = find_rate_upgrade_mac(g, NULL);
if (peer == NULL) {
fst_mgr_printf(MSG_ERROR, "peer address not found");
return;
}
for (i = 0; i < g->slave_cnt; i++) {
res = fst_manager_session_transfer(g->slaves[i].name, peer->addr);
if (res) {
fst_mgr_printf(MSG_ERROR, "session transfer failed");
}
if (fst_dedup_connection(&g->slaves[i], g->acl_fname)) {
fst_mgr_printf(MSG_ERROR, "Cannot dedup iface %s", g->slaves[i].name);
}
}
g->is_duped = FALSE;
}
void fst_rate_upgrade_on_scan_started(const struct fst_group_info *group,
const char *iface)
{
struct rate_upgrade_group *g;
g = find_rate_upgrade_group(group->id);
if (!g)
return;
if (!os_strcmp(iface, g->master))
return;
/* pause traffic poller upon scan on slave interface */
fst_tpoll_pause();
}
void fst_rate_upgrade_on_scan_completed(const struct fst_group_info *group,
const char *iface)
{
struct rate_upgrade_group *g;
g = find_rate_upgrade_group(group->id);
if (!g)
return;
if (!os_strcmp(iface, g->master))
return;
/* resume traffic poller upon scan complete on slave interface */
fst_tpoll_resume();
}
void fst_rate_upgrade_on_signal_change(const struct fst_group_info *group,
const char *iface)
{
struct rate_upgrade_group *g;
g = find_rate_upgrade_group(group->id);
if (!g)
return;
if (!os_strcmp(iface, g->master))
return;
/* it is assumed that slave sends this event upon signal low. Trigger session switch to master */
fst_rate_upgrade_low_traffic(group);
/* restart traffic poller so it can re-trigger high traffic callback when needed */
fst_tpoll_pause();
fst_tpoll_resume();
}

View File

@@ -0,0 +1,70 @@
/*
* FST Manager: Rate Upgrade
*
* Copyright (c) 2015-2016, 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_RATEUPG_H__
#define __FST_RATEUPG_H__
#include "fst_ini_conf.h"
int fst_rate_upgrade_init(struct fst_ini_config *h);
void fst_rate_upgrade_deinit();
int fst_rate_upgrade_add_group(const struct fst_group_info *group);
int fst_rate_upgrade_del_group(const struct fst_group_info *group);
int fst_rate_upgrade_on_connect(const struct fst_group_info *group,
const char *iface, const u8* addr);
int fst_rate_upgrade_on_disconnect(const struct fst_group_info *group,
const char *iface, const u8* addr);
/**
* fst_rate_upgrade_on_switch_completed - called after successful session
* switch. This function will trigger disconnect from peer on old_iface if it's
* not the group's master interface
*
* @group: FST group of the session
* @old_iface: interface that we switch from
* @new_iface: interface that we switch to
* @old_peer_addr: peer's MAC address on old_iface
*/
void fst_rate_upgrade_on_switch_completed(const struct fst_group_info *group,
const char *old_iface, const char *new_iface, const u8* old_peer_addr);
void fst_rate_upgrade_on_release(const struct fst_group_info *group,
const char *iface);
void fst_rate_upgrade_rename_interface(const char *gname, const char *ifname, const char *newifname);
void fst_rate_upgrade_high_traffic(const struct fst_group_info *group);
void fst_rate_upgrade_low_traffic(const struct fst_group_info *group);
void fst_rate_upgrade_on_scan_started(const struct fst_group_info *group,
const char *iface);
void fst_rate_upgrade_on_scan_completed(const struct fst_group_info *group,
const char *iface);
void fst_rate_upgrade_on_signal_change(const struct fst_group_info *group,
const char *iface);
#endif /* __FST_RATEUPG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
* FST TC related routines definitions
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_TC_H__
#define __FST_TC_H__
#include "common/defs.h"
struct fst_tc;
struct fst_tc * fst_tc_create(Boolean is_sta);
int fst_tc_start(struct fst_tc *f, const char *ifname);
void fst_tc_stop(struct fst_tc *f);
void fst_tc_delete(struct fst_tc *f);
int fst_tc_register_iface(struct fst_tc *f, const char *ifname);
void fst_tc_unregister_iface(struct fst_tc *f, const char *ifname);
struct fst_tc_filter_handle {
u16 prio;
char ifname[IFNAMSIZ + 1];
struct dl_list filters_lentry;
};
int fst_tc_add_l2da_filter(struct fst_tc *f, const u8 *mac, int queue_id,
const char *ifname, struct fst_tc_filter_handle *filter_handle);
int fst_tc_del_l2da_filter(struct fst_tc *f,
struct fst_tc_filter_handle *filter_handle);
#endif /* __FST_TC_H__ */

View File

@@ -0,0 +1,293 @@
/*
* FST Manager traffic poller implementation
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#define FST_MGR_COMPONENT "TPOLL"
#include "fst_manager.h"
#include "fst_tpoll.h"
#include "fst_cfgmgr.h"
#include "fst_rateupg.h"
#include "fst_capconfigstore.h"
#define FST_TPOLL_MIN_SAMPLES 5
#define Mbps2Bpms(t) (t * 1000 * 1000 / 1000 / 8)
#define OS_RELTIME2MS(t) (t.sec * 1000 + t.usec / 1000)
static const char FST_TPOLL_LOW_THRESH_KEY_NAME[] = "fst.tpoll.low.thresh.mbps";
#define FST_TPOLL_LOW_TRAFFIC_THRESH "10"
static const char FST_TPOLL_HIGH_THRESH_KEY_NAME[] = "fst.tpoll.high.thresh.mbps";
#define FST_TPOLL_HIGH_TRAFFIC_THRESH "40"
enum fst_tpoll_state {
FST_TPOLL_STATE_DETECTED_NONE,
FST_TPOLL_STATE_DETECTED_HIGH,
FST_TPOLL_STATE_DETECTED_LOW,
};
struct fst_tpoll
{
const struct fst_group_info *group;
char mux_ifname[IFNAMSIZ + 1];
int interval_ms;
int alpha;
int low_thresh_Bpms;
int high_thresh_Bpms;
enum fst_tpoll_state state;
struct os_reltime prev_sample_time;
unsigned long long prev_total_bytes;
int prev_avg; /* bytes/ms */
size_t num_samples;
};
static struct fst_tpoll g_fst_tpoll;
static int fst_tpoll_read_bytes(unsigned long long *total_bytes)
{
char fname[128];
FILE *f;
unsigned long long rx_bytes, tx_bytes;
int res = -1;
if (snprintf(fname, sizeof(fname), "/sys/class/net/%s/statistics/rx_bytes", g_fst_tpoll.mux_ifname) < 0)
return -1;
f = fopen(fname, "r");
if (!f) {
fst_mgr_printf(MSG_ERROR, "failed to open %s", fname);
return -1;
}
if (fscanf(f, "%llu", &rx_bytes) != 1) {
fst_mgr_printf(MSG_ERROR, "failed to read %s", fname);
goto out;
}
fclose(f);
if (snprintf(fname, sizeof(fname), "/sys/class/net/%s/statistics/tx_bytes", g_fst_tpoll.mux_ifname) < 0)
return -1;
f = fopen(fname, "r");
if (!f) {
fst_mgr_printf(MSG_ERROR, "failed to open %s", fname);
return -1;
}
if (fscanf(f, "%llu", &tx_bytes) != 1) {
fst_mgr_printf(MSG_ERROR, "failed to read %s", fname);
goto out;
}
*total_bytes = rx_bytes + tx_bytes;
res = 0;
out:
fclose(f);
return res;
}
static void fst_tpoll_timer(void *eloop_ctx, void *timeout_ctx)
{
unsigned long long total_bytes;
int res, tput, new_avg = g_fst_tpoll.prev_avg;
Boolean detected_high = FALSE, detected_low = FALSE;
res = fst_tpoll_read_bytes(&total_bytes);
if (res)
goto out;
if (total_bytes < g_fst_tpoll.prev_total_bytes) {
fst_mgr_printf(MSG_WARNING, "invalid sample, total_bytes (%llu) < prev_total_bytes (%llu)", total_bytes, g_fst_tpoll.prev_total_bytes);
goto out;
}
if (g_fst_tpoll.num_samples > 0) {
struct os_reltime age;
os_reltime_age(&g_fst_tpoll.prev_sample_time, &age);
/* bytes/ms */
tput = (total_bytes - g_fst_tpoll.prev_total_bytes) / OS_RELTIME2MS(age);
} else {
/* in 1st sample, "prev" fields are uninitialized */
tput = 0;
}
/* Exponential Filtering */
new_avg = (g_fst_tpoll.alpha * tput + (100 - g_fst_tpoll.alpha) * g_fst_tpoll.prev_avg) / 100;
if (++g_fst_tpoll.num_samples < FST_TPOLL_MIN_SAMPLES) {
/* not enough samples to make decisions */
goto out;
}
switch (g_fst_tpoll.state) {
case FST_TPOLL_STATE_DETECTED_NONE:
if (new_avg > g_fst_tpoll.high_thresh_Bpms)
detected_high = TRUE;
else if (new_avg < g_fst_tpoll.low_thresh_Bpms)
detected_low = TRUE;
break;
case FST_TPOLL_STATE_DETECTED_HIGH:
if (new_avg < g_fst_tpoll.low_thresh_Bpms)
detected_low = TRUE;
break;
case FST_TPOLL_STATE_DETECTED_LOW:
if (new_avg > g_fst_tpoll.high_thresh_Bpms)
detected_high = TRUE;
break;
}
if (detected_high) {
fst_mgr_printf(MSG_INFO, "detected high traffic, bytes %llu => %llu, tput %d, avg %d => %d",
g_fst_tpoll.prev_total_bytes, total_bytes, tput * 8 / 1000,
g_fst_tpoll.prev_avg * 8 / 1000, new_avg * 8 / 1000);
fst_rate_upgrade_high_traffic(g_fst_tpoll.group);
g_fst_tpoll.state = FST_TPOLL_STATE_DETECTED_HIGH;
} else if (detected_low) {
fst_mgr_printf(MSG_INFO, "detected low traffic, bytes %llu => %llu, tput %d, avg %d => %d",
g_fst_tpoll.prev_total_bytes, total_bytes, tput * 8 / 1000,
g_fst_tpoll.prev_avg * 8 / 1000, new_avg * 8 / 1000);
fst_rate_upgrade_low_traffic(g_fst_tpoll.group);
g_fst_tpoll.state = FST_TPOLL_STATE_DETECTED_LOW;
}
out:
os_get_reltime(&g_fst_tpoll.prev_sample_time);
g_fst_tpoll.prev_total_bytes = total_bytes;
g_fst_tpoll.prev_avg = new_avg;
eloop_register_timeout(0, g_fst_tpoll.interval_ms * 1000, fst_tpoll_timer, NULL, NULL);
}
int fst_tpoll_start(const struct fst_group_info *group)
{
int len;
if (g_fst_tpoll.group != NULL) {
fst_mgr_printf(MSG_ERROR, "tpoll already started for group %s", g_fst_tpoll.group->id);
return -1;
}
len = fst_cfgmgr_get_mux_ifname(group->id, g_fst_tpoll.mux_ifname, sizeof(g_fst_tpoll.mux_ifname)-1);
if (len == 0) {
fst_mgr_printf(MSG_ERROR, "Cannot get mux ifname");
return -1;
}
fst_mgr_printf(MSG_INFO, "starting");
g_fst_tpoll.group = group;
g_fst_tpoll.num_samples = 0;
g_fst_tpoll.state = FST_TPOLL_STATE_DETECTED_NONE;
g_fst_tpoll.prev_sample_time.sec = g_fst_tpoll.prev_sample_time.usec = 0;
g_fst_tpoll.prev_total_bytes = 0;
g_fst_tpoll.prev_avg = 0;
eloop_register_timeout(0, 0, fst_tpoll_timer, NULL, NULL);
return 0;
}
void fst_tpoll_stop()
{
fst_mgr_printf(MSG_INFO, "stopping");
g_fst_tpoll.group = NULL;
eloop_cancel_timeout(fst_tpoll_timer, NULL, NULL);
}
void fst_tpoll_pause()
{
if (g_fst_tpoll.group == NULL)
return;
fst_mgr_printf(MSG_INFO, "pausing");
eloop_cancel_timeout(fst_tpoll_timer, NULL, NULL);
}
void fst_tpoll_resume()
{
if (g_fst_tpoll.group == NULL)
return;
fst_mgr_printf(MSG_INFO, "resuming");
g_fst_tpoll.num_samples = 0;
g_fst_tpoll.state = FST_TPOLL_STATE_DETECTED_NONE;
g_fst_tpoll.prev_sample_time.sec = g_fst_tpoll.prev_sample_time.usec = 0;
g_fst_tpoll.prev_total_bytes = 0;
g_fst_tpoll.prev_avg = 0;
eloop_register_timeout(0, 0, fst_tpoll_timer, NULL, NULL);
}
int fst_tpoll_init(int interval, int alpha)
{
char buf[64] = { '\0' };
os_memset(&g_fst_tpoll, 0, sizeof(g_fst_tpoll));
g_fst_tpoll.interval_ms = interval;
if (g_fst_tpoll.interval_ms <= 0)
return -1;
g_fst_tpoll.alpha = alpha;
if (g_fst_tpoll.alpha <= 0 || g_fst_tpoll.alpha > 100)
return -1;
fst_get_config_string(FST_TPOLL_LOW_THRESH_KEY_NAME,
FST_TPOLL_LOW_TRAFFIC_THRESH, buf, sizeof(buf));
g_fst_tpoll.low_thresh_Bpms = Mbps2Bpms(strtoul(buf, NULL, 0));
if (g_fst_tpoll.low_thresh_Bpms <= 0)
return -1;
fst_get_config_string(FST_TPOLL_HIGH_THRESH_KEY_NAME,
FST_TPOLL_HIGH_TRAFFIC_THRESH, buf, sizeof(buf));
g_fst_tpoll.high_thresh_Bpms = Mbps2Bpms(strtoul(buf, NULL, 0));
if (g_fst_tpoll.high_thresh_Bpms <= g_fst_tpoll.low_thresh_Bpms)
return -1;
fst_mgr_printf(MSG_INFO, "interval %d, alpha %d, thresh (Bpms) low %d high %d",
g_fst_tpoll.interval_ms, g_fst_tpoll.alpha, g_fst_tpoll.low_thresh_Bpms, g_fst_tpoll.high_thresh_Bpms);
return 0;
}
void fst_tpoll_deinit()
{
eloop_cancel_timeout(fst_tpoll_timer, NULL, NULL);
}

View File

@@ -0,0 +1,45 @@
/*
* FST Manager traffic poller interface definitions
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_TPOLL_H__
#define __FST_TPOLL_H__
#include "fst_ctrl.h"
int fst_tpoll_init(int interval, int alpha);
void fst_tpoll_deinit();
int fst_tpoll_start(const struct fst_group_info *group);
void fst_tpoll_stop();
void fst_tpoll_pause();
void fst_tpoll_resume();
#endif /* __FST_TPOLL_H__ */

View File

@@ -0,0 +1,24 @@
[fst_manager]
ctrl_iface=/data/vendor/wifi/hostapd/global
groups=bond0
[bond0]
interfaces=wlan0,wigig0
mux_type=bonding
mux_ifname=bond0
mux_managed=1
mac_address_by=wlan0
rate_upgrade_master=wlan0
txqueuelen=100
rate_upgrade_acl_file=/data/vendor/wifi/fst_rate_upgrade.accept
[wlan0]
priority=100
default_llt=3600
[wigig0]
priority=110
wpa_group=GCMP
wpa_pairwise=GCMP
hw_mode=ad
channel=2

View File

@@ -0,0 +1,325 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#include "hidl_manager.h"
#include "hidl_return_util.h"
#include "FstGroup.h"
#define FST_MGR_COMPONENT "HIDL"
#include "fst_manager.h"
#include "fst_cfgmgr.h"
extern "C"
{
#include "utils/eloop.h"
}
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using hidl_return_util::validateAndCall;
using namespace vendor::qti::hardware::fstman::V1_0;
using V1_0::IFstGroupCallback;
FstGroup::FstGroup(const char groupName[])
: groupName_(groupName), is_valid_(true)
{}
void FstGroup::invalidate() { is_valid_ = false; }
bool FstGroup::isValid()
{
return is_valid_;
}
Return<void> FstGroup::getName(getName_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::getNameInternal, _hidl_cb);
}
Return<void> FstGroup::registerCallback(
const sp<IFstGroupCallback> &callback,
registerCallback_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::registerCallbackInternal, _hidl_cb, callback);
}
Return<void> FstGroup::listInterfaces(listInterfaces_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::listInterfacesInternal, _hidl_cb);
}
Return<void> FstGroup::isFstModeSupported(isFstModeSupported_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::isFstModeSupportedInternal, _hidl_cb);
}
Return<void> FstGroup::isWifiSonModeSupported(
isWifiSonModeSupported_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::isWifiSonModeSupportedInternal, _hidl_cb);
}
Return<void> FstGroup::getMuxInterfaceName(
getMuxInterfaceName_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::getMuxInterfaceNameInternal, _hidl_cb);
}
Return<void> FstGroup::setMuxInterfaceName(
const hidl_string& name, setMuxInterfaceName_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::setMuxInterfaceNameInternal, _hidl_cb, name);
}
Return<void> FstGroup::enslave(
const hidl_string& ifname, bool enslave,
enslave_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::enslaveInternal, _hidl_cb, ifname, enslave);
}
Return<void> FstGroup::isEnslaved(
const hidl_string& ifname, isEnslaved_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::isEnslavedInternal, _hidl_cb, ifname);
}
Return<void> FstGroup::setMacAddress(
const hidl_array<uint8_t, 6>& mac,
setMacAddress_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::setMacAddressInternal, _hidl_cb, mac);
}
Return<void> FstGroup::isRateUpgradeMaster(
const hidl_string& ifname, isRateUpgradeMaster_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::isRateUpgradeMasterInternal, _hidl_cb, ifname);
}
Return<void> FstGroup::renameInterface(const hidl_string& ifname,
const hidl_string& newifname,
renameInterface_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstGroup::renameInterfaceInternal, _hidl_cb, ifname, newifname);
}
std::pair<FstManagerStatus, std::string> FstGroup::getNameInternal()
{
return {{FstManagerStatusCode::SUCCESS, ""}, groupName_};
}
FstManagerStatus FstGroup::registerCallbackInternal(
const sp<IFstGroupCallback> &callback)
{
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager ||
hidl_manager->addFstGroupCallbackHidlObject(groupName_, callback)) {
return {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
}
return {FstManagerStatusCode::SUCCESS, ""};
}
std::pair<FstManagerStatus, std::vector<hidl_string>>
FstGroup::listInterfacesInternal()
{
std::vector<hidl_string> ifaceNames;
struct fst_group_info gi = {0};
struct fst_iface_info *ifaces = NULL;
int nof_ifaces, i;
os_strlcpy(gi.id, groupName_.c_str(), sizeof(gi.id));
nof_ifaces = fst_cfgmgr_get_group_ifaces(&gi, &ifaces);
if (nof_ifaces < 0)
goto finish;
for (i = 0; i < nof_ifaces; i++)
ifaceNames.emplace_back(ifaces[i].name);
finish:
fst_free(ifaces);
return {{FstManagerStatusCode::SUCCESS, ""}, std::move(ifaceNames)};
}
std::pair<FstManagerStatus, bool> FstGroup::isFstModeSupportedInternal()
{
return {{FstManagerStatusCode::SUCCESS, ""}, true};
}
std::pair<FstManagerStatus, bool> FstGroup::isWifiSonModeSupportedInternal()
{
return {{FstManagerStatusCode::SUCCESS, ""}, false};
}
std::pair<FstManagerStatus, std::string>
FstGroup::getMuxInterfaceNameInternal()
{
char buf[IFNAMSIZ + 1];
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
int res;
std::string muxIfname;
res = fst_cfgmgr_get_mux_ifname(groupName_.c_str(), buf, sizeof(buf));
if (res <= 0)
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
else
muxIfname = buf;
return {status, muxIfname};
}
FstManagerStatus FstGroup::setMuxInterfaceNameInternal(const hidl_string& name)
{
int res;
res = fst_manager_set_mux_iface_name(groupName_.c_str(), name.c_str());
if (res < 0)
return {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
return {FstManagerStatusCode::SUCCESS, ""};
}
FstManagerStatus FstGroup::enslaveInternal(
const hidl_string& ifname, bool enslave)
{
int res;
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
fst_mgr_printf(MSG_INFO, "%s interface %s", enslave ? "enslave" : "release",
ifname.c_str());
res = fst_manager_enslave(groupName_.c_str(), ifname.c_str(), enslave ? TRUE : FALSE);
if (res)
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
return status;
}
std::pair<FstManagerStatus, bool> FstGroup::isEnslavedInternal(
const hidl_string& ifname)
{
Boolean isEnslaved = FALSE;
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
int res;
res = fst_manager_is_enslaved(groupName_.c_str(), ifname.c_str(),
&isEnslaved);
if (res < 0)
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
return {status, (isEnslaved == TRUE)};
}
FstManagerStatus FstGroup::setMacAddressInternal(
const hidl_array<uint8_t, 6>& mac)
{
int res;
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
fst_mgr_printf(MSG_INFO, "%s new mac address " MACSTR, groupName_.c_str(), MAC2STR(mac.data()));
res = fst_manager_set_mac_address(groupName_.c_str(), mac.data());
if (res)
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
return status;
}
std::pair<FstManagerStatus, bool> FstGroup::isRateUpgradeMasterInternal(
const hidl_string& ifname)
{
char buf[IFNAMSIZ + 1];
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
int res;
bool isMaster = false;
res = fst_cfgmgr_get_rate_upgrade_master(groupName_.c_str(), buf,
sizeof(buf));
if (res > 0) {
isMaster = !strncmp(ifname.c_str(), buf, IFNAMSIZ);
} else {
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
}
return {status, isMaster};
}
FstManagerStatus FstGroup::renameInterfaceInternal(const hidl_string& ifname,
const hidl_string& newifname)
{
int res;
FstManagerStatus status = {FstManagerStatusCode::SUCCESS, ""};
fst_mgr_printf(MSG_INFO, "rename group %s interface %s to %s ",
groupName_.c_str(), ifname.c_str(), newifname.c_str());
res = fst_manager_rename_group_interface(groupName_.c_str(),
ifname.c_str(), newifname.c_str());
if (res)
status = {FstManagerStatusCode::FAILURE_UNKNOWN, ""};
return status;
}
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor

View File

@@ -0,0 +1,148 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#ifndef FST_MANAGER_HIDL_FST_GROUP_H
#define FST_MANAGER_HIDL_FST_GROUP_H
#include <array>
#include <vector>
#include <android-base/macros.h>
#include <vendor/qti/hardware/fstman/1.0/IFstGroup.h>
#include <vendor/qti/hardware/fstman/1.0/IFstGroupCallback.h>
extern "C"
{
#include "utils/common.h"
}
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using namespace vendor::qti::hardware::fstman::V1_0;
using android::hardware::hidl_array;
/**
* Implementation of FstGroup hidl object. Each unique hidl
* object is used for control operations on a specific group
* controlled by fst-manager.
*/
class FstGroup : public IFstGroup
{
public:
FstGroup(const char groupName[]);
~FstGroup() override = default;
// HIDL does not provide a built-in mechanism to let the server
// invalidate a HIDL interface object after creation. If any client
// process holds onto a reference to the object in their context,
// any method calls on that reference will continue to be directed to
// the server.
// However FstManager HAL needs to control the lifetime of these
// objects. So, add a public |invalidate| method to all |FstGroup| and
// |FstIface| objects.
// This will be used to mark an object invalid when the corresponding
// iface or network is removed.
// All HIDL method implementations should check if the object is still
// marked valid before processing them.
void invalidate();
bool isValid();
// Hidl methods exposed.
Return<void> getName(getName_cb _hidl_cb) override;
Return<void> registerCallback(
const sp<IFstGroupCallback>& callback,
registerCallback_cb _hidl_cb) override;
Return<void> listInterfaces(listInterfaces_cb _hidl_cb) override;
Return<void> isFstModeSupported(
isFstModeSupported_cb _hidl_cb) override;
Return<void> isWifiSonModeSupported(
isWifiSonModeSupported_cb _hidl_cb) override;
Return<void> getMuxInterfaceName(
getMuxInterfaceName_cb _hidl_cb) override;
Return<void> setMuxInterfaceName(
const hidl_string& name, setMuxInterfaceName_cb _hidl_cb) override;
Return<void> enslave(
const hidl_string& ifname,
bool enslave,
enslave_cb _hidl_cb) override;
Return<void> isEnslaved(
const hidl_string& ifname, isEnslaved_cb _hidl_cb) override;
Return<void> setMacAddress(
const hidl_array<uint8_t, 6>& mac,
setMacAddress_cb _hidl_cb) override;
Return<void> isRateUpgradeMaster(
const hidl_string& ifname,
isRateUpgradeMaster_cb _hidl_cb) override;
Return<void> renameInterface(const hidl_string& ifname,
const hidl_string& newifname,
renameInterface_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
std::pair<FstManagerStatus, std::string> getNameInternal();
FstManagerStatus registerCallbackInternal(
const sp<IFstGroupCallback>& callback);
std::pair<FstManagerStatus, std::vector<hidl_string>>
listInterfacesInternal();
std::pair<FstManagerStatus, bool> isFstModeSupportedInternal();
std::pair<FstManagerStatus, bool> isWifiSonModeSupportedInternal();
std::pair<FstManagerStatus, std::string> getMuxInterfaceNameInternal();
FstManagerStatus setMuxInterfaceNameInternal(const hidl_string& name);
FstManagerStatus enslaveInternal(
const hidl_string& ifname, bool enslave);
std::pair<FstManagerStatus, bool> isEnslavedInternal(
const hidl_string& ifname);
FstManagerStatus setMacAddressInternal(
const hidl_array<uint8_t, 6>& mac);
std::pair<FstManagerStatus, bool> isRateUpgradeMasterInternal(
const hidl_string& ifname);
FstManagerStatus renameInterfaceInternal(const hidl_string& ifname,
const hidl_string& newifname);
// Name of the group this hidl object controls
const std::string groupName_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(FstGroup);
};
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor
#endif // FST_MANAGER_HIDL_FST_GROUP_H

View File

@@ -0,0 +1,187 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#include "hidl_manager.h"
#include "hidl_return_util.h"
#include "FstManager.h"
#define FST_MGR_COMPONENT "HIDL"
#include "fst_manager.h"
#include "fst_cfgmgr.h"
#include "fst_ctrl.h"
extern "C"
{
#include "utils/eloop.h"
}
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using hidl_return_util::validateAndCall;
FstManager::FstManager() {}
bool FstManager::isValid()
{
// This top level object cannot be invalidated.
return true;
}
Return<void> FstManager::getGroup(
const hidl_string& groupName, getGroup_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstManager::getGroupInternal, _hidl_cb, groupName);
}
Return<void> FstManager::listGroups(listGroups_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstManager::listGroupsInternal, _hidl_cb);
}
Return<void> FstManager::setDebugParams(
IFstManager::DebugLevel level, bool show_timestamp,
setDebugParams_cb _hidl_cb)
{
return validateAndCall(
this, FstManagerStatusCode::FAILURE_UNKNOWN,
&FstManager::setDebugParamsInternal, _hidl_cb, level,
show_timestamp);
}
Return<IFstManager::DebugLevel> FstManager::getDebugLevel()
{
// TODO: Add FstManagerStatus in this method return for uniformity with
// the other methods in FstManager HIDL interface.
return (IFstManager::DebugLevel)wpa_debug_level;
}
Return<bool> FstManager::isDebugShowTimestampEnabled()
{
// TODO: Add FstManagerStatus in this method return for uniformity with
// the other methods in FstManager HIDL interface.
return ((wpa_debug_timestamp != 0) ? true : false);
}
Return<void> FstManager::terminate()
{
fst_mgr_printf(MSG_INFO, "Terminating...");
fst_manager_terminate();
return Void();
}
std::pair<FstManagerStatus, sp<IFstGroup>>
FstManager::getGroupInternal(const hidl_string& groupName)
{
if (!isGroupExists(groupName.c_str())) {
return {{FstManagerStatusCode::FAILURE_GROUP_UNKNOWN, ""},
nullptr};
}
HidlManager* hidl_manager = HidlManager::getInstance();
android::sp<IFstGroup> group;
if (!hidl_manager ||
hidl_manager->getFstGroupHidlObjectByName(
groupName, &group)) {
return {{FstManagerStatusCode::FAILURE_UNKNOWN, ""}, group};
}
return {{FstManagerStatusCode::SUCCESS, ""}, group};
}
std::pair<FstManagerStatus, std::vector<hidl_string>>
FstManager::listGroupsInternal()
{
std::vector<hidl_string> groupNames;
struct fst_group_info *groups = NULL;
int res, nof_groups, i;
res = fst_cfgmgr_get_groups(&groups);
if (res < 0) {
goto finish;
}
nof_groups = res;
for (i = 0; i < nof_groups; i++) {
groupNames.emplace_back(groups[i].id);
}
finish:
fst_free(groups);
return {{FstManagerStatusCode::SUCCESS, ""}, std::move(groupNames)};
}
FstManagerStatus FstManager::setDebugParamsInternal(
IFstManager::DebugLevel level, bool show_timestamp)
{
wpa_debug_level = static_cast<uint32_t>(level);
wpa_debug_timestamp = show_timestamp ? 1 : 0;
return {FstManagerStatusCode::SUCCESS, ""};
}
bool FstManager::isGroupExists(const char *groupName)
{
struct fst_group_info *groups = NULL;
int res, nof_groups, i;
bool found;
if (!groupName)
return false;
res = fst_cfgmgr_get_groups(&groups);
if (res < 0) {
return false;
}
nof_groups = res;
found = false;
for (i = 0; i < nof_groups; i++) {
if (!strcmp(groupName, groups[i].id)) {
found = true;
break;
}
}
fst_free(groups);
return found;
}
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor

View File

@@ -0,0 +1,98 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#ifndef FST_MANAGER_HIDL_FSTMANAGER_H
#define FST_MANAGER_HIDL_FSTMANAGER_H
#include <vendor/qti/hardware/fstman/1.0/IFstGroupCallback.h>
#include <vendor/qti/hardware/fstman/1.0/IFstManager.h>
#include <vendor/qti/hardware/fstman/1.0/types.h>
#include <android-base/macros.h>
#include <hidl/Status.h>
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using namespace vendor::qti::hardware::fstman::V1_0;
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::hidl_string;
using android::sp;
/**
* Implementation of the fst manager hidl object. This hidl
* object is used core for global control operations on
* fst manager.
*/
class FstManager : public V1_0::IFstManager
{
public:
FstManager();
~FstManager() override = default;
bool isValid();
// Hidl methods exposed.
Return<void> getGroup(
const hidl_string& groupName, getGroup_cb _hidl_cb) override;
Return<void> listGroups(listGroups_cb _hidl_cb) override;
Return<void> setDebugParams(
IFstManager::DebugLevel level, bool show_timestamp,
setDebugParams_cb _hidl_cb) override;
Return<IFstManager::DebugLevel> getDebugLevel() override;
Return<bool> isDebugShowTimestampEnabled() override;
Return<void> terminate() override;
private:
// Corresponding worker functions for the HIDL methods.
std::pair<FstManagerStatus, sp<IFstGroup>> getGroupInternal(
const hidl_string& groupName);
std::pair<FstManagerStatus, std::vector<hidl_string>>
listGroupsInternal();
FstManagerStatus setDebugParamsInternal(
IFstManager::DebugLevel level, bool show_timestamp);
bool isGroupExists(const char *groupName);
DISALLOW_COPY_AND_ASSIGN(FstManager);
};
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor
#endif // FST_MANAGER_HIDL_FSTMANAGER_H

View File

@@ -0,0 +1,145 @@
/*
* Implements HIDL communication channel for fst manager
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <vendor/qti/hardware/fstman/1.0/IFstManager.h>
#include <vendor/qti/hardware/fstman/1.0/types.h>
#include <hwbinder/IPCThreadState.h>
#include <hwbinder/ProcessState.h>
#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
#define FST_MGR_COMPONENT "HIDL"
#include "fst_manager.h"
#include "fst_cfgmgr.h"
#include "hidl_manager.h"
extern "C"
{
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/os.h"
}
#include "fst_hidl.h"
using android::hardware::hidl_string;
using namespace android;
using android::hardware::configureRpcThreadpool;
using android::hardware::handleTransportPoll;
using android::hardware::setupTransportPolling;
using vendor::qti::hardware::fstman::V1_0::implementation::HidlManager;
using FstManagerStatus = ::vendor::qti::hardware::fstman::V1_0::FstManagerStatus;
using FstManagerStatusCode = ::vendor::qti::hardware::fstman::V1_0::FstManagerStatusCode;
using IFstManager = ::vendor::qti::hardware::fstman::V1_0::IFstManager;
struct fst_hidl_priv {
int hidl_fd;
};
static void fst_hidl_sock_handler(
int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
{
handleTransportPoll(sock);
}
void *fst_hidl_init(void)
{
struct fst_hidl_priv *priv;
HidlManager *hidl_manager;
struct fst_group_info *groups = NULL;
int nof_groups, i;
priv = (fst_hidl_priv *)os_zalloc(sizeof(*priv));
if (!priv) {
fst_mgr_printf(MSG_ERROR, "failed to allocate hidl area");
return NULL;
}
fst_mgr_printf(MSG_INFO, "initializing hidl control");
configureRpcThreadpool(1, true /* callerWillJoin */);
priv->hidl_fd = setupTransportPolling();
if (priv->hidl_fd < 0)
goto err;
fst_mgr_printf(MSG_INFO, "Processing hidl events on FD %d", priv->hidl_fd);
// Look for read events from the hidl socket in the eloop.
if (eloop_register_read_sock(
priv->hidl_fd, fst_hidl_sock_handler, NULL, priv) < 0)
goto err;
hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
goto err;
hidl_manager->registerHidlService();
nof_groups = fst_cfgmgr_get_groups(&groups);
if (nof_groups > 0) {
for (i = 0; i < nof_groups; i++)
hidl_manager->registerGroup(groups[i].id);
fst_free(groups);
}
return priv;
err:
fst_hidl_deinit(priv);
return NULL;
}
void fst_hidl_deinit(void *handle)
{
HidlManager *hidl_manager;
struct fst_group_info *groups = NULL;
int nof_groups, i;
if (!handle)
return;
hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
return;
struct fst_hidl_priv *priv = (struct fst_hidl_priv *)handle;
fst_mgr_printf(MSG_INFO, "Deiniting hidl control");
nof_groups = fst_cfgmgr_get_groups(&groups);
if (nof_groups > 0) {
for (i = 0; i < nof_groups; i++)
hidl_manager->unregisterGroup(groups[i].id);
fst_free(groups);
}
HidlManager::destroyInstance();
eloop_unregister_read_sock(priv->hidl_fd);
os_free(priv);
}

View File

@@ -0,0 +1,55 @@
/*
* Implements HIDL communication channel for fst manager
*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#ifndef __FST_HIDL_H__
#define __FST_HIDL_H__
#include "fst_ctrl.h"
#ifdef __cplusplus
extern "C"
{
#endif
void *fst_hidl_init(void);
void fst_hidl_deinit(void *handle);
void fst_hidl_notify_group_init(const struct fst_group_info *group);
void fst_hidl_notify_group_deinit(const struct fst_group_info *group);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FST_CAPCONFIGSTORE_H__ */

View File

@@ -0,0 +1,355 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#include <algorithm>
#include "hidl_manager.h"
#define FST_MGR_COMPONENT "HIDL"
#include "fst_manager.h"
namespace {
using android::hardware::hidl_array;
using namespace vendor::qti::hardware::fstman::V1_0;
/**
* Add callback to the corresponding list after linking to death on the
* corresponding hidl object reference.
*/
template <class CallbackType>
int registerForDeathAndAddCallbackHidlObjectToList(
const android::sp<CallbackType> &callback,
const std::function<void(const android::sp<CallbackType> &)>
&on_hidl_died_fctor,
std::vector<android::sp<CallbackType>> &callback_list)
{
// TODO link to death
callback_list.push_back(callback);
return 0;
}
template <class ObjectType>
int addHidlObjectToMap(
const std::string &key, const android::sp<ObjectType> object,
std::map<const std::string, android::sp<ObjectType>> &object_map)
{
// Return failure if we already have an object for that |key|.
if (object_map.find(key) != object_map.end())
return 1;
object_map[key] = object;
if (!object_map[key].get())
return 1;
return 0;
}
template <class ObjectType>
int removeHidlObjectFromMap(
const std::string &key,
std::map<const std::string, android::sp<ObjectType>> &object_map)
{
// Return failure if we dont have an object for that |key|.
const auto &object_iter = object_map.find(key);
if (object_iter == object_map.end())
return 1;
object_iter->second->invalidate();
object_map.erase(object_iter);
return 0;
}
template <class CallbackType>
int addGroupCallbackHidlObjectToMap(
const std::string &groupName, const android::sp<CallbackType> &callback,
const std::function<void(const android::sp<CallbackType> &)>
&on_hidl_died_fctor,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
if (groupName.empty())
return 1;
auto group_callback_map_iter = callbacks_map.find(groupName);
if (group_callback_map_iter == callbacks_map.end())
return 1;
auto &group_callback_list = group_callback_map_iter->second;
// Register for death notification before we add it to our list.
return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
callback, on_hidl_died_fctor, group_callback_list);
}
template <class CallbackType>
void removeGroupCallbackHidlObjectFromMap(
const std::string &groupName, const android::sp<CallbackType> &callback,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
if (groupName.empty())
return;
auto group_callback_map_iter = callbacks_map.find(groupName);
if (group_callback_map_iter == callbacks_map.end())
return;
auto &group_callback_list = group_callback_map_iter->second;
group_callback_list.erase(
std::remove(
group_callback_list.begin(), group_callback_list.end(),
callback),
group_callback_list.end());
}
template <class CallbackType>
int removeAllGroupCallbackHidlObjectsFromMap(
const std::string &groupName,
std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
auto group_callback_map_iter = callbacks_map.find(groupName);
if (group_callback_map_iter == callbacks_map.end())
return 1;
// TODO unlink to death
callbacks_map.erase(group_callback_map_iter);
return 0;
}
template <class CallbackType>
void callWithEachGroupCallback(
const std::string &groupName,
const std::function<
android::hardware::Return<void>(android::sp<CallbackType>)> &method,
const std::map<const std::string, std::vector<android::sp<CallbackType>>>
&callbacks_map)
{
if (groupName.empty())
return;
auto group_callback_map_iter = callbacks_map.find(groupName);
if (group_callback_map_iter == callbacks_map.end())
return;
const auto &group_callback_list = group_callback_map_iter->second;
for (const auto &callback : group_callback_list) {
if (!method(callback).isOk()) {
fst_mgr_printf(
MSG_ERROR, "Failed to invoke HIDL group callback");
}
}
}
} // namespace
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using namespace vendor::qti::hardware::fstman::V1_0;
using V1_0::IFstGroupCallback;
HidlManager *HidlManager::instance_ = NULL;
HidlManager *HidlManager::getInstance()
{
if (!instance_)
instance_ = new HidlManager();
return instance_;
}
void HidlManager::destroyInstance()
{
if (instance_)
delete instance_;
instance_ = NULL;
}
int HidlManager::registerHidlService()
{
::android::status_t status;
// Create the main hidl service object and register it.
fstman_object_ = new FstManager();
status = fstman_object_->registerAsService();
if (status != android::NO_ERROR) {
return 1;
}
return 0;
}
/**
* Register a group to hidl manager.
*
* @param groupName the FST group name
*
* @return 0 on success, 1 on failure.
*/
int HidlManager::registerGroup(const char *groupName)
{
if (!groupName)
return 1;
if (addHidlObjectToMap<FstGroup>(
groupName,
new FstGroup(groupName),
fst_group_object_map_)) {
fst_mgr_printf(
MSG_ERROR,
"Failed to register FST group with HIDL "
"control: %s",
groupName);
return 1;
}
fst_group_callbacks_map_[groupName] =
std::vector<android::sp<IFstGroupCallback>>();
// TODO send callback when group created? Currently fst-manager
// does not support dynamic group add/remove.
return 0;
}
/**
* Unregister a group from hidl manager.
*
* @param groupName the FST group name
*
* @return 0 on success, 1 on failure.
*/
int HidlManager::unregisterGroup(const char *groupName)
{
if (!groupName)
return 1;
int success = !removeHidlObjectFromMap(
groupName, fst_group_object_map_);
if (success) {
success = !removeAllGroupCallbackHidlObjectsFromMap(
groupName, fst_group_callbacks_map_);
}
if (!success) {
fst_mgr_printf(
MSG_ERROR,
"Failed to unregister group with HIDL "
"control: %s",
groupName);
return 1;
}
// TODO send callback when group removed? Currently fst-manager
// does not support dynamic group add/remove.
return 0;
}
/**
* Add a new iface callback hidl object reference to our
* interface callback list.
*
* @param ifname Name of the corresponding interface.
* @param callback Hidl reference of the callback object.
*
* @return 0 on success, 1 on failure.
*/
int HidlManager::addFstGroupCallbackHidlObject(
const std::string &groupName,
const android::sp<IFstGroupCallback> &callback)
{
const std::function<void(
const android::sp<IFstGroupCallback> &)>
on_hidl_died_fctor = std::bind(
&HidlManager::removeFstGroupCallbackHidlObject, this, groupName,
std::placeholders::_1);
return addGroupCallbackHidlObjectToMap(
groupName, callback, on_hidl_died_fctor, fst_group_callbacks_map_);
}
/**
* Retrieve the |IFstGroup| hidl object reference using the provided
* group name.
*
* @param groupName Name of the corresponding interface.
* @param group_object Hidl reference corresponding to the group.
*
* @return 0 on success, 1 on failure.
*/
int HidlManager::getFstGroupHidlObjectByName(
const std::string &groupName, android::sp<IFstGroup> *group_object)
{
if (groupName.empty() || !group_object)
return 1;
auto group_object_iter = fst_group_object_map_.find(groupName);
if (group_object_iter == fst_group_object_map_.end())
return 1;
*group_object = group_object_iter->second;
return 0;
}
/**
* Removes the provided FST group callback hidl object reference from
* our group callback list.
*
* @param groupName Name of the corresponding FST group.
* @param callback Hidl reference of the callback object.
*/
void HidlManager::removeFstGroupCallbackHidlObject(
const std::string &groupName,
const android::sp<IFstGroupCallback> &callback)
{
return removeGroupCallbackHidlObjectFromMap(
groupName, callback, fst_group_callbacks_map_);
}
/**
* Helper fucntion to invoke the provided callback method on all the
* registered FST group callback hidl objects for the specified
* |groupName|.
*
* @param groupName Name of the corresponding FST group.
* @param method Pointer to the required hidl method from
* |IFstGroupCallback|.
*/
void HidlManager::callWithEachFstGroupCallback(
const std::string &groupName,
const std::function<Return<void>(android::sp<IFstGroupCallback>)>
&method)
{
callWithEachGroupCallback(groupName, method, fst_group_callbacks_map_);
}
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor

View File

@@ -0,0 +1,135 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#ifndef FST_MANAGER_HIDL_HIDL_MANAGER_H
#define FST_MANAGER_HIDL_HIDL_MANAGER_H
#include <map>
#include <string>
#include "FstManager.h"
#include "FstGroup.h"
extern "C"
{
#include "utils/common.h"
}
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
using namespace vendor::qti::hardware::fstman::V1_0;
using V1_0::IFstManager;
using V1_0::IFstGroupCallback;
/**
* HidlManager is responsible for managing the lifetime of all
* hidl objects created by the fst manager. This is a singleton
* class which is created by the fstman core and can be used
* to get references to the hidl objects.
*/
class HidlManager
{
public:
static HidlManager *getInstance();
static void destroyInstance();
// Methods called from fstman core.
int registerHidlService();
int registerGroup(const char *groupName);
int unregisterGroup(const char *groupName);
void notifyTest(const char *groupName, const char *msg); // DEBUGGING
// Methods called from hidl objects.
int addFstGroupCallbackHidlObject(
const std::string &groupName,
const android::sp<IFstGroupCallback> &callback);
int getFstGroupHidlObjectByName(
const std::string &groupName,
android::sp<IFstGroup> *group_object);
private:
HidlManager() = default;
~HidlManager() = default;
HidlManager(const HidlManager &) = default;
HidlManager &operator=(const HidlManager &) = default;
void removeFstGroupCallbackHidlObject(
const std::string &groupName,
const android::sp<IFstGroupCallback> &callback);
void callWithEachFstGroupCallback(
const std::string &groupName,
const std::function<android::hardware::Return<void>(
android::sp<IFstGroupCallback>)> &method);
// Singleton instance of this class.
static HidlManager *instance_;
// The main hidl service object.
android::sp<FstManager> fstman_object_;
// Map of all the FST group specific hidl objects controlled by
// fst-manager. This map is keyed in by the corresponding
// |groupName|.
std::map<const std::string, android::sp<FstGroup>>
fst_group_object_map_;
// Map of all the callbacks registered for FST group specific
// hidl objects controlled by fst-manager. This map is keyed in by
// the corresponding |groupName|.
std::map<
const std::string,
std::vector<android::sp<IFstGroupCallback>>>
fst_group_callbacks_map_;
};
// The hidl interface uses some values which are the same as internal ones to
// avoid nasty runtime conversion functions. So, adding compile time asserts
// to guard against any internal changes breaking the hidl interface.
static_assert(
static_cast<uint32_t>(IFstManager::DebugLevel::EXCESSIVE) == MSG_EXCESSIVE,
"Debug level value mismatch");
static_assert(
static_cast<uint32_t>(IFstManager::DebugLevel::ERROR) == MSG_ERROR,
"Debug level value mismatch");
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor
#endif // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H

View File

@@ -0,0 +1,124 @@
/*
* hidl interface for fst manager
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*/
#ifndef HIDL_RETURN_UTIL_H_
#define HIDL_RETURN_UTIL_H_
namespace vendor {
namespace qti {
namespace hardware {
namespace fstman {
namespace V1_0 {
namespace implementation {
namespace hidl_return_util {
/**
* These utility functions are used to invoke a method on the provided
* HIDL interface object.
* These functions checks if the provided HIDL interface object is valid.
* a) if valid, Invokes the corresponding internal implementation function of
* the HIDL method. It then invokes the HIDL continuation callback with
* the status and any returned values.
* b) if invalid, invokes the HIDL continuation callback with the
* provided error status and default values.
*/
// Use for HIDL methods which return only an instance of FstManagerStatus.
template <typename ObjT, typename WorkFuncT, typename... Args>
Return<void> validateAndCall(
ObjT* obj, FstManagerStatusCode status_code_if_invalid, WorkFuncT&& work,
const std::function<void(const FstManagerStatus&)>& hidl_cb, Args&&... args)
{
if (obj->isValid()) {
hidl_cb((obj->*work)(std::forward<Args>(args)...));
} else {
hidl_cb({status_code_if_invalid, ""});
}
return Void();
}
// Use for HIDL methods which return instance of FstManagerStatus and a single
// return value.
template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
Return<void> validateAndCall(
ObjT* obj, FstManagerStatusCode status_code_if_invalid, WorkFuncT&& work,
const std::function<void(const FstManagerStatus&, ReturnT)>& hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_pair =
(obj->*work)(std::forward<Args>(args)...);
const FstManagerStatus& status = std::get<0>(ret_pair);
const auto& ret_value = std::get<1>(ret_pair);
hidl_cb(status, ret_value);
} else {
hidl_cb(
{status_code_if_invalid, ""},
typename std::remove_reference<ReturnT>::type());
}
return Void();
}
// Use for HIDL methods which return instance of FstManagerStatus and 2 return
// values.
template <
typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2,
typename... Args>
Return<void> validateAndCall(
ObjT* obj, FstManagerStatusCode status_code_if_invalid, WorkFuncT&& work,
const std::function<void(const FstManagerStatus&, ReturnT1, ReturnT2)>&
hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_tuple =
(obj->*work)(std::forward<Args>(args)...);
const FstManagerStatus& status = std::get<0>(ret_tuple);
const auto& ret_value1 = std::get<1>(ret_tuple);
const auto& ret_value2 = std::get<2>(ret_tuple);
hidl_cb(status, ret_value1, ret_value2);
} else {
hidl_cb(
{status_code_if_invalid, ""},
typename std::remove_reference<ReturnT1>::type(),
typename std::remove_reference<ReturnT2>::type());
}
return Void();
}
} // namespace hidl_return_util
} // namespace implementation
} // namespace V1_0
} // namespace fstman
} // namespace hardware
} // namespace qti
} // namespace vendor
#endif // HIDL_RETURN_UTIL_H_

View File

@@ -0,0 +1,458 @@
/*
* FST CLI based main
*
* Copyright (c) 2015,2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include "utils/common.h"
#include "utils/os.h"
#include "utils/eloop.h"
#include "common/defs.h"
#define FST_MGR_COMPONENT "MAINCLI"
#include "fst_manager.h"
#include "fst_ctrl.h"
#include "fst_cfgmgr.h"
#ifdef ANDROID
#include "fst_capconfigstore.h"
#include "fst_hidl.h"
#endif
#define DEFAULT_FST_INIT_RETRY_PERIOD_SEC 1
#define MAX_CTRL_IFACE_SIZE 256
extern Boolean fst_ctrl_create(const char *ctrl_iface,
unsigned int ping_interval);
extern void fst_ctrl_free(void);
/* globals */
unsigned int fst_debug_level = MSG_INFO;
unsigned int fst_num_of_retries = 20;
unsigned int fst_ping_interval = 1;
Boolean fst_force_nc = FALSE;
static Boolean fst_main_do_loop = FALSE;
static Boolean fst_continuous_loop = FALSE;
static Boolean terminate_signalled = FALSE;
static Boolean init_done = FALSE;
static void fst_manager_signal_terminate(int sig)
{
fst_mgr_printf(MSG_INFO, "termination signal arrived (%d)",
sig);
terminate_signalled = TRUE;
}
static void fst_manager_eloop_terminate(int sig, void *signal_ctx)
{
eloop_terminate();
fst_manager_signal_terminate(sig);
}
void fst_manager_terminate(void)
{
fst_main_do_loop = FALSE;
eloop_terminate();
}
static void usage(const char *prog)
{
printf("Usage: %s [options] [<ctrl_interace_name>]\n", prog);
printf(", where options are:\n"
"\t--version, -V - show version.\n"
"\t--daemon, -B - run in daemon mode. Exit after "
"wpa_supplicant/hostapd quits\n"
"\t--daemonex, -b - continuous daemon mode. Wait for a next "
"wpa_supplicant/hostapd\n"
"\t--config, -c <file> - read the FST configuration from the file\n"
"\t--retries -r <int> - number of session setup retries.\n"
"\t--ping-int -p <int> - CLI ping interval in sec, 0 to disable\n"
"\t--force-nc -n - force non-compliant mode.\n"
"\t--debug, -d - increase debugging verbosity (-dd - more, "
"-ddd - even more)\n"
"\t--logfile, -f <file>- log output to specified file\n"
#ifdef ANDROID
"\t--autogen, -a <mode>- auto-generate fstman.ini for android "
" (mode: 0=supplicant 1=softap)\n"
#endif
"\t--usage, -u - this message\n"
"\t--help, -h - this message\n");
exit(2);
}
void try_to_init(void *eloop_ctx, void *ctx)
{
const char *ctrl_iface = (const char *)ctx;
if (!fst_ctrl_create(ctrl_iface, fst_ping_interval)) {
fst_mgr_printf(MSG_ERROR, "cannot create fst_ctrl");
goto again;
}
if (fst_manager_init()) {
fst_mgr_printf(MSG_ERROR, "cannot init fst manager");
goto error_init;
}
init_done = TRUE;
return;
error_init:
fst_ctrl_free();
again:
eloop_register_timeout(DEFAULT_FST_INIT_RETRY_PERIOD_SEC, 0, try_to_init, NULL, (void*)ctrl_iface);
}
void main_loop(const char *ctrl_iface)
{
if (eloop_register_signal_terminate(fst_manager_eloop_terminate, NULL)) {
fst_mgr_printf(MSG_ERROR, "eloop_register_signal_terminate");
return;
}
eloop_run();
fst_mgr_printf(MSG_INFO, "eloop finished");
if (!fst_continuous_loop)
fst_main_do_loop = FALSE;
if (init_done) {
fst_manager_deinit();
fst_ctrl_free();
init_done = FALSE;
}
}
#ifdef ANDROID
static const char FSTMAN_IFNAME[] = "wlan0";
static const char FSTMAN_WIGIG_IFNAME[] = "wigig0";
static const char FSTMAN_DATA_IFNAME[] = "bond0";
static const char FSTMAN_SAP_IFNAME[] = "wlan0";
static const char FSTMAN_WIGIG_IF_CHANNEL[] = "2";
static const char FST_STA_INTERFACE_KEY_NAME[] =
"fst.wifi.sta.interface";
static const char FST_SAP_INTERFACE_KEY_NAME[] =
"fst.wifi.sap.interface";
static const char FST_DATA_INTERFACE_KEY_NAME[] =
"fst.data.interface";
static const char FST_WIGIG_INTERFACE_KEY_NAME[] =
"fst.wigig.interface";
static const char FST_WIGIG_INTERFACE_CHANNEL_KEY_NAME[] =
"fst.wigig.interface.channel";
static int create_fstman_ini_file(int softap_mode, char *buf, int len)
{
char fst_iface1[64] = { '\0' };
char fst_iface2[64] = { '\0' };
char fst_data_iface[64] = { '\0' };
char fst_wigig_channel[64] = { '\0' };
int result;
if (softap_mode)
fst_get_config_string(FST_SAP_INTERFACE_KEY_NAME,
FSTMAN_SAP_IFNAME,
fst_iface1, sizeof(fst_iface1));
else
fst_get_config_string(FST_STA_INTERFACE_KEY_NAME,
FSTMAN_IFNAME,
fst_iface1, sizeof(fst_iface1));
fst_get_config_string(FST_WIGIG_INTERFACE_KEY_NAME, FSTMAN_WIGIG_IFNAME,
fst_iface2, sizeof(fst_iface2));
fst_get_config_string(FST_DATA_INTERFACE_KEY_NAME, FSTMAN_DATA_IFNAME,
fst_data_iface, sizeof(fst_data_iface));
fst_get_config_string(FST_WIGIG_INTERFACE_CHANNEL_KEY_NAME,
FSTMAN_WIGIG_IF_CHANNEL,
fst_wigig_channel, sizeof(fst_wigig_channel));
result = snprintf(buf, len,
"[fst_manager]\n"
"ctrl_iface=/data/vendor/wifi/hostapd/global\n"
"groups=%s\n" /* bond0 */
"\n"
"[%s]\n" /* bond0 */
"interfaces=%s,%s\n" /* wlan0,wigig0 */
"mux_type=bonding\n"
"mux_ifname=%s\n" /* bond0 */
"mux_managed=1\n"
"mac_address_by=%s\n" /* wlan0 */
"rate_upgrade_master=%s\n" /* wlan0 */
"txqueuelen=100\n"
"rate_upgrade_acl_file=/data/vendor/wifi/fst_rate_upgrade.accept\n"
"\n"
"[%s]\n" /* wlan0 */
"manual_enslave=1\n"
"priority=100\n"
"default_llt=3600\n"
"\n"
"[%s]\n" /* wigig0 */
"manual_enslave=1\n"
"priority=110\n"
"wpa_group=GCMP\n"
"wpa_pairwise=GCMP\n"
"hw_mode=ad\n"
"channel=%s\n",
fst_data_iface,
fst_data_iface,
fst_iface1, fst_iface2,
fst_data_iface,
fst_iface1,
fst_iface1,
fst_iface1,
fst_iface2,
fst_wigig_channel
);
return result;
}
static bool write_fstman_ini_file(const char *fname, const char *contents, int len)
{
FILE *f;
int written;
f = fopen(fname, "w");
if (!f) {
fst_mgr_printf(MSG_ERROR,
"fail to open %s for writing\n", fname);
return false;
}
written = fwrite(contents, 1, len, f);
fclose(f);
if (written != len) {
fst_mgr_printf(MSG_ERROR,
"fail to write to %s\n", fname);
return false;
}
return true;
}
static int fst_manager_gen_fstman_ini(const char *fname, int softap_mode)
{
char cfg[2048];
int len;
len = create_fstman_ini_file(softap_mode, cfg, sizeof(cfg));
if (len <= 0)
return -1;
if (!write_fstman_ini_file(fname, cfg, len))
return -1;
return 0;
}
#endif /* ANDROID */
int main(int argc, char *argv[])
{
const struct option long_opts[] = {
{"version", no_argument, NULL, 'V'},
{"daemon", no_argument, NULL, 'B'},
{"daemonex", no_argument, NULL, 'b'},
{"config", required_argument, NULL, 'c'},
{"retries", required_argument, NULL, 'r'},
{"ping-int", required_argument, NULL, 'p'},
{"force-nc", no_argument, NULL, 'n'},
{"debug", optional_argument, NULL, 'd'},
{"logfile", required_argument, NULL, 'f'},
{"autogen", required_argument, NULL, 'a'},
{"usage", no_argument, NULL, 'u'},
{"help", no_argument, NULL, 'h'},
{}
};
int res = -1;
char short_opts[] = "VBbc:r:nd::f:a:uh";
const char *ctrl_iface = NULL;
char *fstman_config_file = NULL;
int opt, i, mode;
char buf[MAX_CTRL_IFACE_SIZE];
#ifdef ANDROID
void *priv;
#endif
while ((opt = getopt_long_only(argc, argv, short_opts, long_opts, NULL))
!= -1) {
switch (opt) {
case 'V':
printf("FST Manager, version "
FST_MANAGER_VERSION "\n");
exit(0);
break;
case 'B':
fst_main_do_loop = TRUE;
break;
case 'b':
fst_main_do_loop = TRUE;
fst_continuous_loop = TRUE;
break;
case 'c':
if (fstman_config_file != NULL) {
fst_mgr_printf(MSG_ERROR,
"Multiple configurations not allowed\n");
goto error_cfmgr_params;
}
if (optarg != NULL)
fstman_config_file=os_strdup(optarg);
if (fstman_config_file == NULL) {
fst_mgr_printf(MSG_ERROR,
"Filename memory allocation error\n");
goto error_cfmgr_params;
}
break;
case 'r':
if (optarg != NULL)
fst_num_of_retries = strtoul(optarg, NULL, 0);
break;
case 'p':
if (optarg != NULL)
fst_ping_interval = strtoul(optarg, NULL, 0);
break;
case 'n':
fst_force_nc = TRUE;
fst_mgr_printf(MSG_INFO, "Non-compliant FST mode forced\n");
break;
case 'd':
fst_debug_level = MSG_DEBUG;
if (optarg && optarg[0] == 'd') {
fst_debug_level = MSG_MSGDUMP;
if (optarg[1] == 'd')
fst_debug_level = MSG_EXCESSIVE;
}
break;
case 'f':
if (wpa_debug_open_file(optarg)) {
fst_mgr_printf(MSG_ERROR,
"Cannot open log file: %s", optarg);
goto error_cfmgr_params;
}
break;
#ifdef ANDROID
case 'a':
if (fstman_config_file == NULL) {
fst_mgr_printf(MSG_ERROR,
"Config file must be specified\n");
goto error_cfmgr_params;
}
mode = optarg ? strtoul(optarg, NULL, 0) : 0;
res = fst_manager_gen_fstman_ini(
fstman_config_file, mode);
if (res < 0) {
fst_mgr_printf(MSG_ERROR,
"fstman.ini gen failure, err: %d\n",
res);
goto error_cfmgr_params;
}
break;
#endif
case 'u':
case 'h':
case '?':
default:
usage(argv[0]);
break;
}
}
if (!fstman_config_file && argc - optind != 1) {
fst_mgr_printf(MSG_ERROR,
"either ctrl_interace_name or config has to be specified");
usage(argv[0]);
goto error_cfmgr_params;
}
if (fstman_config_file)
i = fst_cfgmgr_init(FST_CONFIG_INI, (void*)fstman_config_file);
else
i = fst_cfgmgr_init(FST_CONFIG_CLI, NULL);
if (i != 0) {
fst_mgr_printf(MSG_ERROR, "FST Configuration error");
goto error_cfmgr_init;
}
if (argc - optind == 1)
ctrl_iface = argv[optind];
else if (!fst_cfgmgr_get_ctrl_iface(buf, sizeof(buf)))
ctrl_iface = buf;
else {
fst_mgr_printf(MSG_ERROR, "cannot get ctrl_iface");
goto error_ctrl_iface;
}
if (eloop_init() != 0) {
fst_mgr_printf(MSG_ERROR, "cannot init eloop");
goto error_eloop_init;
}
#ifdef ANDROID
priv = fst_hidl_init();
if (!priv) {
fst_mgr_printf(MSG_ERROR, "cannot init HIDL");
goto error_hidl_init;
}
#endif
signal(SIGINT, fst_manager_signal_terminate);
signal(SIGTERM, fst_manager_signal_terminate);
while (TRUE) {
eloop_cancel_timeout(try_to_init, NULL, NULL);
eloop_register_timeout(0, 0, try_to_init, NULL, (void*)ctrl_iface);
main_loop(ctrl_iface);
if (!fst_main_do_loop || terminate_signalled)
break;
signal(SIGINT, fst_manager_signal_terminate);
signal(SIGTERM, fst_manager_signal_terminate);
os_sleep(DEFAULT_FST_INIT_RETRY_PERIOD_SEC, 0);
}
res = 0;
#ifdef ANDROID
fst_hidl_deinit(priv);
#endif
error_hidl_init:
eloop_destroy();
error_eloop_init:
error_ctrl_iface:
fst_cfgmgr_deinit();
error_cfmgr_init:
error_cfmgr_params:
wpa_debug_close_file();
os_free(fstman_config_file);
return res;
}

View File

@@ -0,0 +1,164 @@
/*
* FST Dbus based main
*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#define FST_MGR_COMPONENT "MDBS"
#include "fst_manager.h"
#include "utils/common.h"
#include "utils/os.h"
#include "common/defs.h"
#include "fst_ctrl.h"
#include <glib.h>
#include <glib-unix.h>
struct wpa_ctrl;
extern Boolean fst_ctrl_create(void);
extern void fst_ctrl_free(void);
/* globals */
unsigned int fst_debug_level = MSG_INFO;
unsigned int fst_num_of_retries = 3;
Boolean fst_force_nc = FALSE;
static gboolean register_signal_terminate(GSourceFunc handler,
gpointer user_data)
{
guint id = g_unix_signal_add(SIGINT, handler, user_data);
if (id > 0) {
id = g_unix_signal_add(SIGTERM, handler, user_data);
if (id > 0)
return TRUE;
}
return FALSE;
}
static gboolean fst_manager_terminate(gpointer user_data)
{
GMainLoop *loop = user_data;
fst_mgr_printf(MSG_INFO, "termination signal arrived");
g_main_loop_quit(loop);
return FALSE;
}
static void usage(const char *prog)
{
g_print("Usage: %s [options] <ctrl_interace_name>\n", prog);
g_print(", where options are:\n"
"\t--version, -V - show version.\n"
"\t--retries -r - number of session setup retries.\n"
"\t--debug, -d - debug output\n"
"\t--usage, -u - this message\n"
"\t--help, -h - this message\n");
exit(2);
}
int main(int argc, char *argv[])
{
GMainLoop *loop;
const struct option long_opts[] = {
{"version", 0, NULL, 'V'},
{"retries", 1, NULL, 'r'},
{"force-nc", 0, NULL, 'n'},
{"debug", 2, NULL, 'd'},
{"usage", 0, NULL, 'u'},
{"help", 0, NULL, 'h'},
{}
};
char short_opts[] = "vr:nd::uh";
int opt;
while ((opt = getopt_long_only(argc, argv, short_opts, long_opts, NULL))
!= -1) {
switch (opt) {
case 'V':
printf("FST Manager, version "
FST_MANAGER_VERSION "\n");
exit(0);
break;
case 'r':
fst_num_of_retries = strtoul(optarg, NULL, 0);
break;
case 'n':
fst_force_nc = TRUE;
fst_mgr_printf(MSG_INFO,
"Non-compliant FST mode forced\n");
break;
case 'd':
fst_debug_level = MSG_EXCESSIVE;
if (optarg)
fst_debug_level = strtoul(optarg, NULL, 0);
break;
case 'u':
case 'h':
case '?':
default:
usage(argv[0]);
break;
}
}
loop = g_main_loop_new(NULL, FALSE);
if (!loop) {
fst_mgr_printf(MSG_ERROR, "cannot create main loop");
goto error_g_main_loop_new;
}
if (!fst_ctrl_create()) {
fst_mgr_printf(MSG_ERROR, "cannot create fst_ctrl");
goto error_fst_ctrl_create;
}
if (!register_signal_terminate(fst_manager_terminate, loop)) {
fst_mgr_printf(MSG_ERROR, "cannot register termination signal handler");
goto error_register_signal_terminate;
}
g_main_loop_run(loop);
fst_mgr_printf(MSG_INFO, "main loop finished");
error_register_signal_terminate:
fst_ctrl_free();
error_fst_ctrl_create:
g_main_loop_unref(loop);
error_g_main_loop_new:
return 0;
}

View File

@@ -0,0 +1,46 @@
# Copyright (c) 2019, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# 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.
# FST Manager with hostapd (softap) - all settings inside ini file
service fstman /vendor/bin/fstman -B -ddd -c /data/vendor/wifi/fstman.ini -a 1
user wifi
group wifi
capabilities NET_ADMIN NET_RAW
class main
disabled
oneshot
# FST Manager with supplicant - connect to supplicant socket
service fstman_wlan0 /vendor/bin/fstman -B -ddd -c /data/vendor/wifi/fstman.ini \
-a 0 @android:vendor_wpa_wlan0
user wifi
group wifi
capabilities NET_ADMIN NET_RAW
interface vendor.qti.hardware.fstman@1.0::IFstManager default
class main
disabled
oneshot