freewtp/src/wtp.c

1564 lines
47 KiB
C

#include "wtp.h"
#include "network.h"
#include "protocol.h"
#include "capwap_dfa.h"
#include "array.h"
#include "list.h"
#include "element.h"
#include "dtls.h"
#include "dfa.h"
#include "radio.h"
#include <arpa/inet.h>
#include <ev.h>
#include <libconfig.h>
struct wtp_t g_wtp;
/* Local param */
#define WTP_STANDARD_NAME "Unknown WTP"
#define WTP_STANDARD_LOCATION "Unknown Location"
#define WTP_RADIO_INITIALIZATION_INTERVAL 1000
static char g_configurationfile[260] = WTP_STANDARD_CONFIGURATION_FILE;
/* Alloc WTP */
static int wtp_init(void)
{
/* Init WTP with default value */
memset(&g_wtp, 0, sizeof(struct wtp_t));
/* Standard running mode is standalone */
g_wtp.standalone = 1;
strcpy(g_wtp.wlanprefix, WTP_PREFIX_DEFAULT_NAME);
/* Standard name */
g_wtp.name.name = (uint8_t*)capwap_duplicate_string(WTP_STANDARD_NAME);
g_wtp.location.value = (uint8_t*)capwap_duplicate_string(WTP_STANDARD_LOCATION);
/* State machine */
g_wtp.state = CAPWAP_START_STATE;
g_wtp.discoveryinterval = WTP_DISCOVERY_INTERVAL;
g_wtp.echointerval = WTP_ECHO_INTERVAL;
/* Socket */
capwap_network_init(&g_wtp.net);
/* Standard configuration */
g_wtp.boarddata.boardsubelement =
capwap_array_create(sizeof(struct capwap_wtpboarddata_board_subelement), 0, 1);
g_wtp.descriptor.encryptsubelement =
capwap_array_create(sizeof(struct capwap_wtpdescriptor_encrypt_subelement), 0, 0);
g_wtp.descriptor.descsubelement =
capwap_array_create(sizeof(struct capwap_wtpdescriptor_desc_subelement), 0, 1);
g_wtp.binding = CAPWAP_WIRELESS_BINDING_NONE;
g_wtp.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
g_wtp.transport.type = CAPWAP_UDP_TRANSPORT;
g_wtp.statisticstimer.timer = WTP_STATISTICSTIMER_INTERVAL / 1000;
g_wtp.sta_max_inactivity = WIFI_STATIONS_DEFAULT_STA_MAX_INACTIVITY;
g_wtp.mactype.type = CAPWAP_LOCALMAC;
g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
/* DTLS */
g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
/* Tx fragment packets */
g_wtp.requestfragmentpacket = capwap_list_create();
g_wtp.responsefragmentpacket = capwap_list_create();
wtp_reset_state();
/* AC information */
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN;
g_wtp.acdiscoveryrequest = 1;
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(struct addr_capwap), 0, 0);
g_wtp.acpreferedarray = capwap_array_create(sizeof(struct addr_capwap), 0, 0);
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1);
/* Radios */
wtp_radio_init();
return 1;
}
/* Destroy WTP */
static void wtp_destroy(void) {
int i;
/* Dtls */
capwap_crypt_freecontext(&g_wtp.dtlscontext);
/* Free standard configuration */
capwap_array_free(g_wtp.descriptor.encryptsubelement);
for (i = 0; i < g_wtp.descriptor.descsubelement->count; i++) {
struct capwap_wtpdescriptor_desc_subelement* element = (struct capwap_wtpdescriptor_desc_subelement*)capwap_array_get_item_pointer(g_wtp.descriptor.descsubelement, i);
if (element->data) {
capwap_free(element->data);
}
}
for (i = 0; i < g_wtp.boarddata.boardsubelement->count; i++) {
struct capwap_wtpboarddata_board_subelement* element = (struct capwap_wtpboarddata_board_subelement*)capwap_array_get_item_pointer(g_wtp.boarddata.boardsubelement, i);
if (element->data) {
capwap_free(element->data);
}
}
capwap_array_free(g_wtp.descriptor.descsubelement);
capwap_array_free(g_wtp.boarddata.boardsubelement);
/* Free fragments packet */
capwap_list_free(g_wtp.requestfragmentpacket);
capwap_list_free(g_wtp.responsefragmentpacket);
/* Free list AC */
capwap_array_free(g_wtp.acdiscoveryarray);
capwap_array_free(g_wtp.acpreferedarray);
wtp_free_discovery_response_array();
capwap_array_free(g_wtp.acdiscoveryresponse);
/* Free local message elements */
capwap_free(g_wtp.name.name);
capwap_free(g_wtp.location.value);
/* Free radios */
wtp_radio_free();
}
/* */
static void wtp_add_default_acaddress() {
struct addr_capwap address;
/* Broadcast IPv4 */
memset(&address, 0, sizeof(struct addr_capwap));
address.resolved = 1;
address.sockaddr.sin.sin_family = AF_INET;
address.sockaddr.sin.sin_addr.s_addr = INADDR_BROADCAST;
address.sockaddr.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &address, sizeof(struct addr_capwap));
/* Multicast IPv4 */
/* TODO */
/* Multicast IPv6 */
/* TODO */
}
/* usage */
static void wtp_print_usage(void) {
printf("FreeWTP CAPWAP-WTP daemon\n"
"\n"
"Usage: capwap-wtp [OPTION...]\n"
"\n"
" -h show this information\n"
" -V show version information\n"
" -c CONFIG use configuration-file CONFIG\n"
"\n");
}
static int wtp_parsing_radio_qos_configuration(config_setting_t *elem, const char *section,
struct capwap_80211_wtpqos_subelement *qos)
{
config_setting_t *sect;
LIBCONFIG_LOOKUP_INT_ARG val;
sect = config_setting_get_member(elem, section);
if (!sect)
return 0;
if (config_setting_lookup_int(sect, "queuedepth", &val) != CONFIG_TRUE ||
val > 255)
return 0;
qos->queuedepth = val;
if (config_setting_lookup_int(sect, "cwmin", &val) != CONFIG_TRUE ||
val > 65565)
return 0;
qos->cwmin = val;
if (config_setting_lookup_int(sect, "cwmax", &val) != CONFIG_TRUE ||
val > 65565)
return 0;
qos->cwmax = val;
if (config_setting_lookup_int(sect, "aifs", &val) != CONFIG_TRUE ||
val > 255)
return 0;
qos->aifs = val;
if (config_setting_lookup_int(sect, "priority8021p", &val) != CONFIG_TRUE ||
val > 7)
return 0;
qos->priority8021p = val;
if (config_setting_lookup_int(sect, "dscp", &val) != CONFIG_TRUE ||
val > 255)
return 0;
qos->dscp = val;
return 1;
}
/* */
static int wtp_parsing_radio_80211n_cfg(config_setting_t *elem,
struct wtp_radio *radio)
{
config_setting_t* sect;
int boolval;
LIBCONFIG_LOOKUP_INT_ARG intval;
sect = config_setting_get_member(elem, "ieee80211n");
if (!sect) {
log_printf(LOG_ERR, "application.radio.ieee80211n not found");
return 0;
}
radio->n_radio_cfg.radioid = radio->radioid;
if (config_setting_lookup_bool(sect, "a-msdu", &boolval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.a-msdu not found or wrong type");
return 0;
}
if (boolval)
radio->n_radio_cfg.flags |= CAPWAP_80211N_RADIO_CONF_A_MSDU;
if (config_setting_lookup_bool(sect, "a-mpdu", &boolval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.a-mpdu not found or wrong type");
return 0;
}
if (boolval)
radio->n_radio_cfg.flags |= CAPWAP_80211N_RADIO_CONF_A_MPDU;
if (config_setting_lookup_bool(sect, "require-ht", &boolval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.require-ht not found or wrong type");
return 0;
}
if (boolval)
radio->n_radio_cfg.flags |= CAPWAP_80211N_RADIO_CONF_11N_ONLY;
if (config_setting_lookup_bool(sect, "short-gi", &boolval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.short-gi not found or wrong type");
return 0;
}
if (boolval)
radio->n_radio_cfg.flags |= CAPWAP_80211N_RADIO_CONF_SHORT_GUARD_INTERVAL;
if (config_setting_lookup_bool(sect, "ht40", &boolval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.ht40 not found or wrong type");
return 0;
}
if (!boolval)
radio->n_radio_cfg.flags |= CAPWAP_80211N_RADIO_CONF_20MHZ_BANDWITH;
if (config_setting_lookup_int(sect, "max-sup-mcs", &intval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.max-sup-mcs not found or wrong type");
return 0;
}
radio->n_radio_cfg.maxsupmcs = intval;
if (config_setting_lookup_int(sect, "max-mand-mcs", &intval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.max-mand-mcs not found or wrong type");
return 0;
}
radio->n_radio_cfg.maxmandmcs = intval;
if (config_setting_lookup_int(sect, "tx-antenna", &intval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.tx-antenna not found or wrong type");
return 0;
}
radio->n_radio_cfg.txant = intval;
if (config_setting_lookup_int(sect, "rx-antenna", &intval) != CONFIG_TRUE) {
log_printf(LOG_ERR, "application.radio.ieee80211n.rx-antenna not found or wrong type");
return 0;
}
radio->n_radio_cfg.rxant = intval;
return 1;
}
/* */
static int wtp_parsing_radio_configuration(config_setting_t* configElement, struct wtp_radio* radio) {
int i, len, cnt;
int configBool;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
config_setting_t* configItems;
config_setting_t* configSection;
/* Physical radio mode */
radio->radioinformation.radioid = radio->radioid;
if (config_setting_lookup_string(configElement, "mode", &configString) != CONFIG_TRUE)
return 0;
len = strlen(configString);
if (!len)
return 0;
for (i = 0; i < len; i++) {
switch (configString[i]) {
case 'a':
radio->radioinformation.radiotype |= CAPWAP_RADIO_TYPE_80211A;
break;
case 'b':
radio->radioinformation.radiotype |= CAPWAP_RADIO_TYPE_80211B;
break;
case 'g':
radio->radioinformation.radiotype |= CAPWAP_RADIO_TYPE_80211G;
break;
case 'n':
radio->radioinformation.radiotype |= CAPWAP_RADIO_TYPE_80211N;
break;
default:
return 0;
}
}
/* Antenna */
configSection = config_setting_get_member(configElement, "antenna");
if (!configSection)
return 0;
radio->antenna.radioid = radio->radioid;
if (config_setting_lookup_bool(configSection, "diversity", &configBool) != CONFIG_TRUE)
return 0;
radio->antenna.diversity = (configBool ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE);
if (config_setting_lookup_string(configSection, "combiner", &configString) != CONFIG_TRUE)
return 0;
if (!strcmp(configString, "left")) {
radio->antenna.combiner = CAPWAP_ANTENNA_COMBINER_SECT_LEFT;
} else if (!strcmp(configString, "right")) {
radio->antenna.combiner = CAPWAP_ANTENNA_COMBINER_SECT_RIGHT;
} else if (!strcmp(configString, "omni")) {
radio->antenna.combiner = CAPWAP_ANTENNA_COMBINER_SECT_OMNI;
} else if (!strcmp(configString, "mimo")) {
radio->antenna.combiner = CAPWAP_ANTENNA_COMBINER_SECT_MIMO;
} else {
return 0;
}
configItems = config_setting_get_member(configSection, "selection");
if (!configItems)
return 0;
cnt = config_setting_length(configItems);
if (cnt == 0 || cnt > CAPWAP_ANTENNASELECTIONS_MAXLENGTH)
return 0;
for (i = 0; i < cnt; i++) {
uint8_t* selection = (uint8_t*)capwap_array_get_item_pointer(radio->antenna.selections, i);
configString = config_setting_get_string_elem(configItems, i);
if (!strcmp(configString, "internal")) {
*selection = CAPWAP_ANTENNA_INTERNAL;
} else if (!strcmp(configString, "external")) {
*selection = CAPWAP_ANTENNA_EXTERNAL;
} else {
return 0;
}
}
/* Multi-Domain Capability */
configSection = config_setting_get_member(configElement, "multidomaincapability");
if (configSection) {
radio->multidomaincapability.radioid = radio->radioid;
if (config_setting_lookup_int(configSection, "firstchannel", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 65535)
return 0;
radio->multidomaincapability.firstchannel = (uint16_t)configInt;
if (config_setting_lookup_int(configSection, "numberchannels", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 65535)
return 0;
radio->multidomaincapability.numberchannels = (uint16_t)configInt;
if (config_setting_lookup_int(configSection, "maxtxpower", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 65535)
return 0;
radio->multidomaincapability.maxtxpowerlevel = (uint16_t)configInt;
}
/* MAC Operation */
radio->macoperation.radioid = radio->radioid;
if (config_setting_lookup_int(configElement, "rtsthreshold", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 2347)
return 0;
radio->macoperation.rtsthreshold = (uint16_t)configInt;
if (config_setting_lookup_int(configElement, "shortretry", &configInt) != CONFIG_TRUE ||
configInt < 2 || configInt > 255)
return 0;
radio->macoperation.shortretry = (uint8_t)configInt;
if (config_setting_lookup_int(configElement, "longretry", &configInt) != CONFIG_TRUE ||
configInt < 2 || configInt > 255)
return 0;
radio->macoperation.longretry = (uint8_t)configInt;
if (config_setting_lookup_int(configElement, "fragmentationthreshold", &configInt) != CONFIG_TRUE ||
configInt < 256 || configInt > 2346)
return 0;
radio->macoperation.fragthreshold = (uint16_t)configInt;
if (config_setting_lookup_int(configElement, "txmsdulifetime", &configInt) != CONFIG_TRUE ||
configInt == 0)
return 0;
radio->macoperation.txmsdulifetime = (uint32_t)configInt;
if (config_setting_lookup_int(configElement, "rxmsdulifetime", &configInt) != CONFIG_TRUE ||
configInt == 0)
return 0;
radio->macoperation.rxmsdulifetime = (uint32_t)configInt;
/* Supported rate */
radio->supportedrates.radioid = radio->radioid;
configItems = config_setting_get_member(configElement, "supportedrates");
if (!configItems)
return 0;
cnt = config_setting_length(configItems);
if (cnt < CAPWAP_SUPPORTEDRATES_MINLENGTH ||
cnt > CAPWAP_SUPPORTEDRATES_MAXLENGTH)
return 0;
radio->supportedrates.supportedratescount = (uint8_t)cnt;
for (i = 0; i < cnt; i++) {
config_setting_t *elem;
int value;
elem = config_setting_get_elem(configItems, i);
switch (config_setting_type(elem)) {
case CONFIG_TYPE_INT:
value = config_setting_get_int(elem) * 2;
break;
case CONFIG_TYPE_FLOAT:
value = config_setting_get_float(elem) * 2;
break;
default:
return 0;
}
if (value < 2 || value > 127)
return 0;
radio->supportedrates.supportedrates[i] = (uint8_t)value;
}
/* TX Power */
configSection = config_setting_get_member(configElement, "txpower");
if (configSection) {
radio->txpower.radioid = radio->radioid;
if (config_setting_lookup_int(configSection, "current", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 10000)
return 0;
radio->txpower.currenttxpower = (uint16_t)configInt;
configItems = config_setting_get_member(configSection, "supported");
if (configItems != NULL) {
cnt = config_setting_length(configItems);
if (cnt == 0 || cnt > CAPWAP_TXPOWERLEVEL_MAXLENGTH)
return 0;
radio->txpowerlevel.radioid = radio->radioid;
radio->txpowerlevel.numlevels = (uint8_t)cnt;
for (i = 0; i < cnt; i++) {
int value = config_setting_get_int_elem(configItems, i);
if (value < 0 || value > 10000)
return 0;
radio->txpowerlevel.powerlevel[i] = (uint8_t)value;
}
}
}
/* WTP Radio Configuration */
radio->radioconfig.radioid = radio->radioid;
if (config_setting_lookup_bool(configElement, "shortpreamble", &configBool) != CONFIG_TRUE)
return 0;
radio->radioconfig.shortpreamble = (configBool ? CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_ENABLE : CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_DISABLE);
if (config_setting_lookup_int(configElement, "maxbssid", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 16)
return 0;
radio->radioconfig.maxbssid = (uint8_t)configInt;
if (config_setting_lookup_string(configElement, "bssprefixname", &configString) != CONFIG_TRUE ||
strlen(configString) >= IFNAMSIZ)
return 0;
strcpy(radio->wlanprefix, configString);
if (config_setting_lookup_int(configElement, "dtimperiod", &configInt) != CONFIG_TRUE ||
configInt == 0 || configInt > 256)
return 0;
radio->radioconfig.dtimperiod = (uint8_t)configInt;
if (config_setting_lookup_int(configElement, "beaconperiod", &configInt) != CONFIG_TRUE ||
configInt == 0 ||configInt > 65535)
return 0;
radio->radioconfig.beaconperiod = (uint16_t)configInt;
if (config_setting_lookup_string(configElement, "country", &configString) != CONFIG_TRUE ||
strlen(configString) != 2)
return 0;
radio->radioconfig.country[0] = (uint8_t)configString[0];
radio->radioconfig.country[1] = (uint8_t)configString[1];
if (config_setting_lookup_bool(configElement, "shortpreamble", &configBool) == CONFIG_TRUE)
radio->radioconfig.country[2] = (uint8_t)(configBool ? 'O' : 'I');
else
radio->radioconfig.country[2] = (uint8_t)' ';
/* QoS */
radio->qos.radioid = radio->radioid;
configSection = config_setting_get_member(configElement, "qos");
if (!configSection)
return 0;
if (config_setting_lookup_int(configSection, "taggingpolicy", &configInt) != CONFIG_TRUE ||
configInt > 255)
return 0;
radio->qos.taggingpolicy = (uint8_t)configInt;
if (wtp_parsing_radio_qos_configuration(configSection, "voice", &radio->qos.qos[3]) == 0 ||
wtp_parsing_radio_qos_configuration(configSection, "video", &radio->qos.qos[2]) == 0 ||
wtp_parsing_radio_qos_configuration(configSection, "besteffort", &radio->qos.qos[0]) == 0 ||
wtp_parsing_radio_qos_configuration(configSection, "background", &radio->qos.qos[1]) == 0)
return 0;
if (radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211N) {
if (wtp_parsing_radio_80211n_cfg(configElement, radio) == 0)
return 0;
}
return 1;
}
/* */
static int wtp_parsing_radio_section_configuration(config_setting_t* configSetting)
{
int i;
int configBool;
const char* configString;
struct wtp_radio* radio;
const struct wifi_capability* capability;
int count = config_setting_length(configSetting);
if (g_wtp.binding != CAPWAP_WIRELESS_BINDING_IEEE80211)
return 1;
for (i = 0; i < count; i++) {
if (!IS_VALID_RADIOID(g_wtp.radios->count + 1)) {
log_printf(LOG_ERR, "Exceeded max number of radio device");
return 0;
}
/* */
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
if (!configElement)
continue;
if (config_setting_lookup_string(configElement, "device", &configString) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.radio.device not found");
return 0;
}
if (*configString && (strlen(configString) >= IFNAMSIZ)) {
log_printf(LOG_ERR, "Invalid configuration file, application.radio.device string length exceeded");
return 0;
}
/* Create new radio device */
radio = wtp_radio_create_phy();
strcpy(radio->device, configString);
if (config_setting_lookup_bool(configElement, "enabled", &configBool) != CONFIG_TRUE
|| !configBool)
continue;
/* Retrieve radio capability */
if (wtp_parsing_radio_configuration(configElement, radio) == 0) {
log_printf(LOG_ERR, "Invalid configuration file, application.radio");
return 0;
}
/* Initialize radio device */
if (config_setting_lookup_string(configElement, "driver", &configString) != CONFIG_TRUE ||
!*configString ||
(strlen(configString) >= WIFI_DRIVER_NAME_SIZE))
continue;
radio->devicehandle = wifi_device_connect(radio->device, configString);
if (!radio->devicehandle) {
radio->status = WTP_RADIO_HWFAILURE;
log_printf(LOG_WARNING, "Unable to register radio device: %s - %s", radio->device, configString);
}
radio->status = WTP_RADIO_ENABLED;
log_printf(LOG_INFO, "Register radioid %d with radio device: %s - %s", radio->radioid, radio->device, configString);
/* Update radio capability with device query */
capability = wifi_device_getcapability(radio->devicehandle);
if (!capability)
continue;
uint8_t bssid;
/* Create interface */
for (bssid = 0; bssid < radio->radioconfig.maxbssid; bssid++) {
char wlanname[IFNAMSIZ];
struct wtp_radio_wlan *wlan;
sprintf(wlanname, "%s%02d.%02d", radio->wlanprefix, (int)radio->radioid, (int)bssid + 1);
if (wifi_iface_index(wlanname)) {
log_printf(LOG_ERR, "interface %s already exists", wlanname);
return 0;
}
/* */
wlan = (struct wtp_radio_wlan *)capwap_array_get_item_pointer(radio->wlan, bssid + 1);
wlan->in_use = 0;
wlan->radio = radio;
wlan->wlanhandle = wifi_wlan_create(radio->devicehandle, wlanname);
if (!wlan->wlanhandle) {
log_printf(LOG_ERR, "Unable to create interface: %s", wlanname);
return 0;
}
log_printf(LOG_DEBUG, "Created wlan interface: %s", wlanname);
}
}
/* Update radio status */
g_wtp.descriptor.maxradios = g_wtp.radios->count;
g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use();
return 1;
}
/* Parsing boardinfo configuration */
static int wtp_parsing_cfg_boardinfo_element(config_t *config)
{
config_setting_t *configSetting;
int count, i;
/* Set Element Boardinfo of WTP */
configSetting = config_lookup(config, "application.boardinfo.element");
if (!configSetting)
return 1;
count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
config_setting_t *configElement;
const char *configName;
const char *configValue;
int lengthValue;
struct capwap_wtpboarddata_board_subelement *element;
configElement = config_setting_get_elem(configSetting, i);
if (!configElement)
continue;
if (config_setting_lookup_string(configElement, "name", &configName) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.boardinfo.element.name not found");
return 0;
}
if (config_setting_lookup_string(configElement, "value", &configValue) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.boardinfo.element.value not found");
return 0;
}
lengthValue = strlen(configValue);
if (lengthValue >= CAPWAP_BOARD_SUBELEMENT_MAXDATA) {
log_printf(LOG_ERR, "Invalid configuration file, application.boardinfo.element.value string length exceeded");
return 0;
}
element = (struct capwap_wtpboarddata_board_subelement*)capwap_array_get_item_pointer(g_wtp.boarddata.boardsubelement, g_wtp.boarddata.boardsubelement->count);
if (strcmp(configName, "model") == 0) {
element->type = CAPWAP_BOARD_SUBELEMENT_MODELNUMBER;
element->length = lengthValue;
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
} else if (strcmp(configName, "serial") == 0) {
element->type = CAPWAP_BOARD_SUBELEMENT_SERIALNUMBER;
element->length = lengthValue;
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
} else if (strcmp(configName, "id") == 0) {
element->type = CAPWAP_BOARD_SUBELEMENT_ID;
element->length = lengthValue;
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
} else if (strcmp(configName, "revision") == 0) {
element->type = CAPWAP_BOARD_SUBELEMENT_REVISION;
element->length = lengthValue;
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
} else if (strcmp(configName, "macaddress") == 0) {
const char* configType;
if (config_setting_lookup_string(configElement, "type", &configType) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.boardinfo.element.type not found");
return 0;
}
if (strcmp(configType, "interface") == 0) {
char macaddress[MACADDRESS_EUI64_LENGTH];
/* Retrieve macaddress */
element->type = CAPWAP_BOARD_SUBELEMENT_MACADDRESS;
element->length = capwap_get_macaddress_from_interface(configValue, macaddress);
if (!element->length || ((element->length != MACADDRESS_EUI64_LENGTH) && (element->length != MACADDRESS_EUI48_LENGTH))) {
log_printf(LOG_ERR, "Invalid configuration file, unable found macaddress of interface: '%s'", configValue);
return 0;
}
element->data = (uint8_t*)capwap_clone((void*)macaddress, element->length);
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.boardinfo.element.type value");
return 0;
}
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.boardinfo.element.name value");
return 0;
}
}
return 1;
}
/* Set info descriptor of WTP */
static int wtp_parsing_cfg_descriptor_info(config_t *config)
{
config_setting_t *configSetting;
int count, i;
configSetting = config_lookup(config, "application.descriptor.info");
if (!configSetting)
return 1;
count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
config_setting_t *configElement;
LIBCONFIG_LOOKUP_INT_ARG configVendor;
const char *configType;
const char *configValue;
int lengthValue;
unsigned short type;
struct capwap_wtpdescriptor_desc_subelement *desc;
configElement = config_setting_get_elem(configSetting, i);
if (!configElement)
continue;
if (config_setting_lookup_int(configElement, "idvendor", &configVendor) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.descriptor.info.idvendor not found");
return 0;
}
if (config_setting_lookup_string(configElement, "type", &configType) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.descriptor.info.type not found");
return 0;
}
if (config_setting_lookup_string(configElement, "value", &configValue) != CONFIG_TRUE) {
log_printf(LOG_ERR, "Invalid configuration file, element application.descriptor.info.value not found");
return 0;
}
lengthValue = strlen(configValue);
if (lengthValue >= CAPWAP_WTPDESC_SUBELEMENT_MAXDATA) {
log_printf(LOG_ERR, "Invalid configuration file, application.descriptor.info.value string length exceeded");
return 0;
}
if (!strcmp(configType, "hardware")) {
type = CAPWAP_WTPDESC_SUBELEMENT_HARDWAREVERSION;
} else if (!strcmp(configType, "software")) {
type = CAPWAP_WTPDESC_SUBELEMENT_SOFTWAREVERSION;
} else if (!strcmp(configType, "boot")) {
type = CAPWAP_WTPDESC_SUBELEMENT_BOOTVERSION;
} else if (!strcmp(configType, "other")) {
type = CAPWAP_WTPDESC_SUBELEMENT_OTHERVERSION;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.descriptor.info.type value");
return 0;
}
desc = (struct capwap_wtpdescriptor_desc_subelement*)capwap_array_get_item_pointer(g_wtp.descriptor.descsubelement, g_wtp.descriptor.descsubelement->count);
desc->vendor = (unsigned long)configVendor;
desc->type = type;
desc->data = (uint8_t*)capwap_duplicate_string(configValue);
}
return 1;
}
static int wtp_parsing_mac_type(const char *str, int *type)
{
if (!strcmp(str, "localmac")) {
*type |= 0x01;
} else if (!strcmp(str, "splitmac")) {
*type |= 0x02;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.mactype value");
return 0;
}
return 1;
}
/* Parsing configuration */
static int wtp_parsing_configuration_1_0(config_t* config) {
int i;
int configBool;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
config_setting_t* configSetting;
/* Logging configuration */
if (config_lookup_bool(config, "logging.enable", &configBool) == CONFIG_TRUE) {
if (!configBool) {
capwap_logging_verboselevel(LOG_NONE);
capwap_logging_disable_allinterface();
} else {
if (config_lookup_string(config, "logging.level", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "fatal")) {
capwap_logging_verboselevel(LOG_EMERG);
} else if (!strcmp(configString, "error")) {
capwap_logging_verboselevel(LOG_ERR);
} else if (!strcmp(configString, "warning")) {
capwap_logging_verboselevel(LOG_WARNING);
} else if (!strcmp(configString, "info")) {
capwap_logging_verboselevel(LOG_INFO);
} else if (!strcmp(configString, "debug")) {
capwap_logging_verboselevel(LOG_DEBUG);
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown logging.level value");
return 0;
}
}
/* Logging output interface */
configSetting = config_lookup(config, "logging.output");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
/* Disable output interface */
capwap_logging_disable_allinterface();
/* Enable selected interface */
for (i = 0; i < count; i++) {
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
if ((configElement != NULL) && (config_setting_lookup_string(configElement, "mode", &configString) == CONFIG_TRUE)) {
if (!strcmp(configString, "stdout")) {
capwap_logging_enable_console(0);
} else if (!strcmp(configString, "stderr")) {
capwap_logging_enable_console(1);
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown logging.output value");
return 0;
}
}
}
}
}
}
/* Set running mode */
if (config_lookup_bool(config, "application.standalone", &configBool) == CONFIG_TRUE) {
g_wtp.standalone = ((configBool != 0) ? 1 : 0);
}
/* Set name of WTP */
if (config_lookup_string(config, "application.name", &configString) == CONFIG_TRUE) {
if (strlen(configString) > CAPWAP_WTPNAME_MAXLENGTH) {
log_printf(LOG_ERR, "Invalid configuration file, application.name string length exceeded");
return 0;
}
capwap_free(g_wtp.name.name);
g_wtp.name.name = (uint8_t*)capwap_duplicate_string(configString);
}
/* Set location of WTP */
if (config_lookup_string(config, "application.location", &configString) == CONFIG_TRUE) {
if (strlen(configString) > CAPWAP_LOCATION_MAXLENGTH) {
log_printf(LOG_ERR, "Invalid configuration file, application.location string length exceeded");
return 0;
}
capwap_free(g_wtp.location.value);
g_wtp.location.value = (uint8_t*)capwap_duplicate_string(configString);
}
/* Set binding of WTP */
if (config_lookup_string(config, "application.binding", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "802.11")) {
g_wtp.binding = CAPWAP_WIRELESS_BINDING_IEEE80211;
} else if (!strcmp(configString, "EPCGlobal")) {
g_wtp.binding = CAPWAP_WIRELESS_BINDING_EPCGLOBAL;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.binding value");
return 0;
}
}
/* Initialize binding */
switch (g_wtp.binding) {
case CAPWAP_WIRELESS_BINDING_NONE: {
break;
}
case CAPWAP_WIRELESS_BINDING_IEEE80211: {
/* Initialize wifi binding driver */
log_printf(LOG_INFO, "Initializing wifi binding engine");
if (wifi_driver_init()) {
log_printf(LOG_EMERG, "Unable initialize wifi binding engine");
return 0;
}
break;
}
default: {
log_printf(LOG_EMERG, "Unable initialize unknown binding engine: %hu", g_wtp.binding);
return 0;
}
}
/* Set tunnelmode of WTP */
if (config_lookup(config, "application.tunnelmode") != NULL) {
g_wtp.mactunnel.mode = 0;
if (config_lookup_bool(config, "application.tunnelmode.nativeframe", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
g_wtp.mactunnel.mode |= CAPWAP_WTP_NATIVE_FRAME_TUNNEL;
}
}
if (config_lookup_bool(config, "application.tunnelmode.ethframe", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
g_wtp.mactunnel.mode |= CAPWAP_WTP_8023_FRAME_TUNNEL;
}
}
if (config_lookup_bool(config, "application.tunnelmode.localbridging", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING;
}
}
}
/* Set mactype of WTP */
configSetting = config_lookup(config, "application.mactype");
if (configSetting != NULL) {
int type = 0;
switch (config_setting_type(configSetting)) {
case CONFIG_TYPE_ARRAY: {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++)
if (!wtp_parsing_mac_type(config_setting_get_string_elem(configSetting, i), &type))
return 0;
break;
}
case CONFIG_TYPE_STRING:
if (!wtp_parsing_mac_type(config_setting_get_string(configSetting), &type))
return 0;
break;
default:
log_printf(LOG_ERR, "Invalid configuration file, invalid application.mactype type");
return 0;
}
switch (type) {
case 0x01:
g_wtp.mactype.type = CAPWAP_LOCALMAC;
break;
case 0x02:
g_wtp.mactype.type = CAPWAP_SPLITMAC;
break;
case 0x03:
g_wtp.mactype.type = CAPWAP_LOCALANDSPLITMAC;
break;
default:
log_printf(LOG_ERR, "Invalid configuration file, invalid application.mactype value");
return 0;
}
}
/* Set VendorID Boardinfo of WTP */
if (config_lookup_int(config, "application.boardinfo.idvendor", &configInt) == CONFIG_TRUE) {
g_wtp.boarddata.vendor = (unsigned long)configInt;
}
if (wtp_parsing_cfg_boardinfo_element(config) != 1)
return 0;
/* Set WLAN WTP */
if (config_lookup_string(config, "wlan.prefix", &configString) == CONFIG_TRUE) {
int length = strlen(configString);
if ((length > 0) && (length < WTP_PREFIX_NAME_MAX_LENGTH)) {
strcpy(g_wtp.wlanprefix, configString);
} else {
log_printf(LOG_ERR, "Invalid configuration file, wlan.prefix string length exceeded");
return 0;
}
}
/* Set Radio WTP */
configSetting = config_lookup(config, "application.radio");
if (configSetting)
if (wtp_parsing_radio_section_configuration(configSetting) == 0)
return 0;
/* Set encryption of WTP */
configSetting = config_lookup(config, "application.descriptor.encryption");
if (configSetting != NULL) {
unsigned short capability = 0;
int count = config_setting_length(configSetting);
struct capwap_wtpdescriptor_encrypt_subelement* encrypt;
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
for (i = 0; i < count; i++) {
const char* encryption = config_setting_get_string_elem(configSetting, i);
if (encryption != NULL) {
if (!strcmp(encryption, "802.11_AES")) {
capability |= 0; /* TODO */
} else if (!strcmp(encryption, "802.11_TKIP")) {
capability |= 0; /* TODO */
} else {
log_printf(LOG_ERR, "Invalid configuration file, invalid application.descriptor.encryption value");
return 0;
}
}
}
}
/* */
encrypt = (struct capwap_wtpdescriptor_encrypt_subelement*)capwap_array_get_item_pointer(g_wtp.descriptor.encryptsubelement, g_wtp.descriptor.encryptsubelement->count);
encrypt->wbid = g_wtp.binding;
encrypt->capabilities = capability;
} else {
log_printf(LOG_ERR, "Invalid configuration file, application.descriptor.encryption not found");
return 0;
}
/* Set info descriptor of WTP */
if (wtp_parsing_cfg_descriptor_info(config) != 1)
return 0;
/* Set ECN of WTP */
if (config_lookup_string(config, "application.ecn", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "full")) {
g_wtp.ecn.flag = CAPWAP_FULL_ECN_SUPPORT;
} else if (!strcmp(configString, "limited")) {
g_wtp.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.ecn value");
return 0;
}
}
/* Set Timer of WTP */
if (config_lookup_int(config, "application.timer.statistics", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65536)) {
g_wtp.statisticstimer.timer = (unsigned short)configInt;
} else {
log_printf(LOG_ERR, "Invalid configuration file, invalid application.timer.statistics value");
return 0;
}
}
if (config_lookup_int(config, "application.timer.inactivity", &configInt) == CONFIG_TRUE) {
if ((configInt < 0) || (configInt > 3600)) {
log_printf(LOG_ERR, "Invalid configuration file, "
"invalid application.timer.inactivity value");
return 0;
}
g_wtp.sta_max_inactivity = (unsigned short)configInt;
}
/* Set DTLS of WTP */
if (config_lookup_bool(config, "application.dtls.enable", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
struct capwap_dtls_param dtlsparam;
/* Init dtls param */
memset(&dtlsparam, 0, sizeof(struct capwap_dtls_param));
dtlsparam.type = CAPWAP_DTLS_CLIENT;
/* Set DTLS Policy of WTP */
if (config_lookup(config, "application.dtls.dtlspolicy") != NULL) {
g_wtp.validdtlsdatapolicy = 0;
if (config_lookup_bool(config, "application.dtls.dtlspolicy.cleardatachannel", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
}
}
if (config_lookup_bool(config, "application.dtls.dtlspolicy.dtlsdatachannel", &configBool) == CONFIG_TRUE) {
if (configBool != 0) {
g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED;
}
}
}
/* Set DTLS type of WTP */
if (config_lookup_string(config, "application.dtls.type", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "x509")) {
dtlsparam.mode = CAPWAP_DTLS_MODE_CERTIFICATE;
} else if (!strcmp(configString, "presharedkey")) {
dtlsparam.mode = CAPWAP_DTLS_MODE_PRESHAREDKEY;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.dtls.type value");
return 0;
}
}
/* Set DTLS configuration of WTP */
if (dtlsparam.mode == CAPWAP_DTLS_MODE_CERTIFICATE) {
if (config_lookup_string(config, "application.dtls.x509.calist", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.fileca = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.x509.certificate", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.filecert = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.x509.privatekey", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.filekey = capwap_duplicate_string(configString);
}
}
/* */
if (dtlsparam.cert.fileca && dtlsparam.cert.filecert && dtlsparam.cert.filekey) {
if (capwap_crypt_createcontext(&g_wtp.dtlscontext, &dtlsparam)) {
g_wtp.enabledtls = 1;
}
}
/* Free dtls param */
if (dtlsparam.cert.fileca) {
capwap_free(dtlsparam.cert.fileca);
}
if (dtlsparam.cert.filecert) {
capwap_free(dtlsparam.cert.filecert);
}
if (dtlsparam.cert.filekey) {
capwap_free(dtlsparam.cert.filekey);
}
} else if (dtlsparam.mode == CAPWAP_DTLS_MODE_PRESHAREDKEY) {
if (config_lookup_string(config, "application.dtls.presharedkey.identity", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.presharedkey.identity = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.presharedkey.pskkey", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.presharedkey.pskkey = capwap_duplicate_string(configString);
}
}
/* */
if (dtlsparam.presharedkey.identity && dtlsparam.presharedkey.pskkey) {
if (capwap_crypt_createcontext(&g_wtp.dtlscontext, &dtlsparam)) {
g_wtp.enabledtls = 1;
}
}
/* Free dtls param */
if (dtlsparam.presharedkey.identity) {
capwap_free(dtlsparam.presharedkey.identity);
}
if (dtlsparam.presharedkey.pskkey) {
capwap_free(dtlsparam.presharedkey.pskkey);
}
}
if (!g_wtp.enabledtls) {
return 0;
}
}
}
/* Set interface binding of WTP */
if (config_lookup_string(config, "application.network.binding", &configString) == CONFIG_TRUE) {
if (strlen(configString) > (IFNAMSIZ - 1)) {
log_printf(LOG_ERR, "Invalid configuration file, application.network.binding string length exceeded");
return 0;
}
strcpy(g_wtp.net.bindiface, configString);
}
/* Set mtu of WTP */
if (config_lookup_int(config, "application.network.mtu", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65536)) {
g_wtp.mtu = (unsigned short)configInt;
} else {
log_printf(LOG_ERR, "Invalid configuration file, invalid application.network.mtu value");
return 0;
}
}
/* Set transport of WTP */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) {
g_wtp.transport.type = CAPWAP_UDP_TRANSPORT;
} else if (!strcmp(configString, "udplite")) {
g_wtp.transport.type = CAPWAP_UDPLITE_TRANSPORT;
} else {
log_printf(LOG_ERR, "Invalid configuration file, unknown application.network.transport value");
return 0;
}
}
/* Set search discovery of WTP */
if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) {
g_wtp.acdiscoveryrequest = (configBool ? 1 : 0);
}
/* Set discovery host of WTP */
configSetting = config_lookup(config, "application.acdiscovery.host");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct addr_capwap acaddr;
memset(&acaddr, 0, sizeof(struct addr_capwap));
strncpy(acaddr.fqdn, address, CAPWAP_MAX_FQDN_SIZE-1);
acaddr.resolved = 0;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr.sockaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr.sockaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr.sockaddr, CAPWAP_CONTROL_PORT);
}
acaddr.resolved = 1;
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_STATIC;
} else {
log_printf(LOG_INFO, "%s:%d Could not resolve application.acdiscovery.host %s", __FILE__, __LINE__, address);
}
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &acaddr, sizeof(struct addr_capwap));
}
}
}
/* Set preferred ac of WTP */
configSetting = config_lookup(config, "application.acprefered.host");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct addr_capwap acaddr;
memset(&acaddr, 0, sizeof(struct addr_capwap));
strncpy(acaddr.fqdn, address, CAPWAP_MAX_FQDN_SIZE-1);
acaddr.resolved = 0;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr.sockaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr.sockaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr.sockaddr, CAPWAP_CONTROL_PORT);
}
acaddr.resolved = 1;
} else {
log_printf(LOG_INFO, "%s:%d Could not resolve application.acprefered.host %s", __FILE__, __LINE__, acaddr.fqdn);
}
memcpy(capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedarray->count), &acaddr, sizeof(struct addr_capwap));
}
}
}
return 1;
}
/* Parsing configuration */
static int wtp_parsing_configuration(config_t* config) {
const char* configString;
if (config_lookup_string(config, "version", &configString) == CONFIG_TRUE) {
if (strcmp(configString, "1.0") == 0) {
return wtp_parsing_configuration_1_0(config);
}
log_printf(LOG_ERR, "Invalid configuration file, '%s' is not supported", configString);
} else {
log_printf(LOG_ERR, "Invalid configuration file, unable to found version tag");
}
return 0;
}
/* handle command line arguments */
static void wtp_handle_argv(int argc, char **argv) {
int c;
ASSERT(argc >= 0);
ASSERT(argv != NULL);
/* Parsing command line */
opterr = 0;
while ((c = getopt(argc, argv, "hc:V")) != -1) {
switch (c) {
case 'h': {
wtp_print_usage();
exit(0);
}
case 'V': {
printf("%s\n", VERSION);
exit(0);
}
case 'c': {
if (strlen(optarg) < sizeof(g_configurationfile)) {
strcpy(g_configurationfile, optarg);
break;
} else {
printf("Invalid -%c argument\n", optopt);
exit(1);
}
}
case '?': {
if (optopt == 'c') {
printf("Option -%c requires an argument\n", optopt);
} else {
printf("Unknown option character `\\x%x'\n", optopt);
}
wtp_print_usage();
exit(1);
}
}
}
}
/* Load configuration */
static int wtp_load_configuration() {
int result = 0;
config_t config;
/* Init libconfig */
config_init(&config);
/* Load configuration */
if (config_read_file(&config, g_configurationfile) == CONFIG_TRUE) {
result = wtp_parsing_configuration(&config);
} else {
result = -1;
log_printf(LOG_ERR, "Unable load the configuration file '%s': %s (%d)", g_configurationfile, config_error_text(&config), config_error_line(&config));
}
/* Free libconfig */
config_destroy(&config);
return result;
}
/* Init WTP */
static int wtp_configure(void) {
/* If not set try IPv6 */
if (g_wtp.net.localaddr.ss.ss_family == AF_UNSPEC) {
g_wtp.net.localaddr.ss.ss_family = AF_INET6;
}
/* If request add default acdiscovery */
if (!g_wtp.acdiscoveryarray->count) {
wtp_add_default_acaddress();
}
/* Bind control address */
if (capwap_bind_sockets(&g_wtp.net)) {
log_printf(LOG_EMERG, "Cannot bind control address");
return WTP_ERROR_NETWORK;
}
wtp_socket_io_start();
return CAPWAP_SUCCESSFUL;
}
static void wtp_wait_radio_ready_timeout_cb(EV_P_ ev_timer *w, int revents)
{
ev_break (EV_A_ EVBREAK_ONE);
}
/* */
static void wtp_wait_radio_ready(void)
{
ev_timer timeout;
ev_timer_init(&timeout, wtp_wait_radio_ready_timeout_cb,
WTP_RADIO_INITIALIZATION_INTERVAL / 1000, 0.);
ev_timer_start(EV_DEFAULT_UC_ &timeout);
ev_run(EV_DEFAULT_UC_ 0);
}
/* */
int wtp_update_radio_in_use() {
/* TODO */
return g_wtp.radios->count;
}
/* Main*/
int main(int argc, char** argv) {
int value;
int result = CAPWAP_SUCCESSFUL;
wtp_handle_argv(argc, argv);
ev_default_loop(0);
/* Init logging */
capwap_logging_init();
capwap_logging_verboselevel(LOG_ERR);
capwap_logging_enable_console(1);
/* Init capwap */
if (geteuid() != 0) {
log_printf(LOG_EMERG, "Request root privileges");
result = CAPWAP_REQUEST_ROOT;
goto out_close_log;
}
/* Init random generator */
capwap_init_rand();
/* Init crypt */
if (capwap_crypt_init()) {
result = CAPWAP_CRYPT_ERROR;
log_printf(LOG_EMERG, "Error to init crypt engine");
goto out_check_memory;
}
/* Init WTP */
if (!wtp_init()) {
result = WTP_ERROR_SYSTEM_FAILER;
log_printf(LOG_EMERG, "Error to init WTP engine");
goto out_release_crypto;
}
/* Read configuration file */
value = wtp_load_configuration();
if (value < 0) {
result = WTP_ERROR_LOAD_CONFIGURATION;
log_printf(LOG_EMERG, "Error to load configuration");
goto out_destroy_wtp;
} else if (value == 0)
/* error already reported in config parser */
goto out_destroy_wtp;
if (!g_wtp.standalone) {
capwap_daemon();
/* Console logging is disabled in daemon mode */
capwap_logging_disable_console();
log_printf(LOG_INFO, "Running WTP in daemon mode");
}
/* Wait the initialization of radio interfaces */
log_printf(LOG_INFO, "Wait for the initialization of radio interfaces");
wtp_wait_radio_ready();
/* Connect WTP with kernel module */
if (wtp_kmod_init()) {
log_printf(LOG_EMERG, "Unable to connect with kernel module");
goto out_close_radio;
}
log_printf(LOG_INFO, "CAPWAP WTP kernel module connected");
/* */
log_printf(LOG_INFO, "Startup WTP");
/* Complete configuration WTP */
result = wtp_configure();
if (result == CAPWAP_SUCCESSFUL) {
/* Running WTP */
result = wtp_dfa_running();
/* Close sockets */
wtp_socket_io_stop();
capwap_close_sockets(&g_wtp.net);
}
/* Disconnect kernel module */
wtp_kmod_free();
/* */
log_printf(LOG_INFO, "Terminate WTP");
out_close_radio:
/* Close radio */
wtp_radio_close();
/* Free binding */
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
log_printf(LOG_INFO, "Free wifi binding engine");
wifi_driver_free();
}
out_destroy_wtp:
/* Free memory */
wtp_destroy();
out_release_crypto:
/* Free crypt */
capwap_crypt_free();
out_check_memory:
/* Check memory leak */
if (capwap_check_memory_leak(1)) {
if (result == CAPWAP_SUCCESSFUL)
result = WTP_ERROR_MEMORY_LEAK;
}
out_close_log:
/* Close logging */
capwap_logging_close();
return result;
}