2013-05-01 14:52:55 +02:00
|
|
|
#include "wtp.h"
|
|
|
|
#include "capwap_network.h"
|
|
|
|
#include "capwap_protocol.h"
|
|
|
|
#include "capwap_dfa.h"
|
|
|
|
#include "capwap_array.h"
|
2013-05-27 21:33:23 +02:00
|
|
|
#include "capwap_list.h"
|
2013-05-01 14:52:55 +02:00
|
|
|
#include "capwap_element.h"
|
|
|
|
#include "capwap_dtls.h"
|
|
|
|
#include "wtp_dfa.h"
|
2014-02-08 18:03:38 +01:00
|
|
|
#include "wtp_radio.h"
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <libconfig.h>
|
|
|
|
|
|
|
|
struct wtp_t g_wtp;
|
|
|
|
|
|
|
|
/* Local param */
|
2014-03-02 19:31:27 +01:00
|
|
|
#define WTP_STANDARD_NAME "Unknown WTP"
|
|
|
|
#define WTP_STANDARD_LOCATION "Unknown Location"
|
|
|
|
#define WTP_RADIO_INITIALIZATION_INTERVAL 1000
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
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));
|
|
|
|
|
2013-06-16 12:09:57 +02:00
|
|
|
/* Standard running mode is standalone */
|
|
|
|
g_wtp.standalone = 1;
|
2013-12-20 23:14:34 +01:00
|
|
|
strcpy(g_wtp.wlanprefix, WTP_PREFIX_DEFAULT_NAME);
|
2013-06-16 12:09:57 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Standard name */
|
2013-06-09 17:41:52 +02:00
|
|
|
g_wtp.name.name = (uint8_t*)capwap_duplicate_string(WTP_STANDARD_NAME);
|
|
|
|
g_wtp.location.value = (uint8_t*)capwap_duplicate_string(WTP_STANDARD_LOCATION);
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* State machine */
|
2014-03-02 19:31:27 +01:00
|
|
|
g_wtp.state = CAPWAP_START_STATE;
|
|
|
|
g_wtp.discoveryinterval = WTP_DISCOVERY_INTERVAL;
|
|
|
|
g_wtp.echointerval = WTP_ECHO_INTERVAL;
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2014-02-19 19:16:33 +01:00
|
|
|
/* */
|
|
|
|
g_wtp.timeout = capwap_timeout_init();
|
2014-03-02 19:31:27 +01:00
|
|
|
g_wtp.idtimercontrol = capwap_timeout_createtimer(g_wtp.timeout);
|
|
|
|
g_wtp.idtimerecho = capwap_timeout_createtimer(g_wtp.timeout);
|
|
|
|
g_wtp.idtimerkeepalive = capwap_timeout_createtimer(g_wtp.timeout);
|
|
|
|
g_wtp.idtimerkeepalivedead = capwap_timeout_createtimer(g_wtp.timeout);
|
2014-02-19 19:16:33 +01:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Socket */
|
|
|
|
capwap_network_init(&g_wtp.net);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Standard configuration */
|
2013-06-08 17:26:10 +02:00
|
|
|
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);
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
g_wtp.binding = CAPWAP_WIRELESS_BINDING_NONE;
|
|
|
|
|
|
|
|
g_wtp.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
|
|
|
|
g_wtp.transport.type = CAPWAP_UDP_TRANSPORT;
|
2014-03-02 19:31:27 +01:00
|
|
|
g_wtp.statisticstimer.timer = WTP_STATISTICSTIMER_INTERVAL / 1000;
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
g_wtp.mactype.type = CAPWAP_LOCALMAC;
|
|
|
|
g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* DTLS */
|
|
|
|
g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Tx fragment packets */
|
|
|
|
g_wtp.mtu = CAPWAP_MTU_DEFAULT;
|
2013-05-27 21:33:23 +02:00
|
|
|
g_wtp.requestfragmentpacket = capwap_list_create();
|
|
|
|
g_wtp.responsefragmentpacket = capwap_list_create();
|
2013-12-04 22:25:16 +01:00
|
|
|
g_wtp.remoteseqnumber = WTP_INIT_REMOTE_SEQUENCE;
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
/* AC information */
|
2013-06-09 17:41:52 +02:00
|
|
|
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN;
|
2013-05-01 14:52:55 +02:00
|
|
|
g_wtp.acdiscoveryrequest = 1;
|
2014-09-10 21:58:23 +02:00
|
|
|
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
|
|
|
|
g_wtp.acpreferedarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
|
2013-06-08 17:26:10 +02:00
|
|
|
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1);
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Radios */
|
2013-12-20 23:14:34 +01:00
|
|
|
wtp_radio_init();
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Destroy WTP */
|
|
|
|
static void wtp_destroy(void) {
|
2013-06-09 17:41:52 +02:00
|
|
|
int i;
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Dtls */
|
|
|
|
capwap_crypt_freecontext(&g_wtp.dtlscontext);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Free standard configuration */
|
|
|
|
capwap_array_free(g_wtp.descriptor.encryptsubelement);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
capwap_array_free(g_wtp.descriptor.descsubelement);
|
|
|
|
capwap_array_free(g_wtp.boarddata.boardsubelement);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Free fragments packet */
|
2013-05-27 21:33:23 +02:00
|
|
|
capwap_list_free(g_wtp.requestfragmentpacket);
|
|
|
|
capwap_list_free(g_wtp.responsefragmentpacket);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Free list AC */
|
|
|
|
capwap_array_free(g_wtp.acdiscoveryarray);
|
|
|
|
capwap_array_free(g_wtp.acpreferedarray);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
wtp_free_discovery_response_array();
|
|
|
|
capwap_array_free(g_wtp.acdiscoveryresponse);
|
2014-02-19 19:16:33 +01:00
|
|
|
capwap_timeout_free(g_wtp.timeout);
|
2013-06-09 17:41:52 +02:00
|
|
|
|
|
|
|
/* Free local message elements */
|
|
|
|
capwap_free(g_wtp.name.name);
|
|
|
|
capwap_free(g_wtp.location.value);
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Free radios */
|
2013-12-20 23:14:34 +01:00
|
|
|
wtp_radio_free();
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2014-09-10 21:58:23 +02:00
|
|
|
static void wtp_add_default_acaddress() {
|
|
|
|
union sockaddr_capwap address;
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Broadcast IPv4 */
|
2014-09-10 21:58:23 +02:00
|
|
|
memset(&address, 0, sizeof(union sockaddr_capwap));
|
|
|
|
address.sin.sin_family = AF_INET;
|
|
|
|
address.sin.sin_addr.s_addr = INADDR_BROADCAST;
|
|
|
|
address.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
|
|
|
|
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &address, sizeof(union sockaddr_capwap));
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Multicast IPv4 */
|
|
|
|
/* TODO */
|
2014-09-10 21:58:23 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Multicast IPv6 */
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Help */
|
|
|
|
static void wtp_print_usage(void) {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
2013-09-22 22:28:59 +02:00
|
|
|
/* */
|
|
|
|
static int wtp_parsing_radio_configuration(config_setting_t* configElement, struct wtp_radio* radio) {
|
|
|
|
int i;
|
|
|
|
int configBool;
|
2014-02-08 18:03:38 +01:00
|
|
|
LIBCONFIG_LOOKUP_INT_ARG configInt;
|
2013-09-22 22:28:59 +02:00
|
|
|
const char* configString;
|
|
|
|
config_setting_t* configItems;
|
|
|
|
config_setting_t* configSection;
|
|
|
|
|
|
|
|
/* Physical radio mode */
|
2013-09-24 19:14:57 +02:00
|
|
|
radio->radioinformation.radioid = radio->radioid;
|
2013-09-22 22:28:59 +02:00
|
|
|
if (config_setting_lookup_string(configElement, "mode", &configString) == CONFIG_TRUE) {
|
|
|
|
int length = strlen(configString);
|
|
|
|
if (!length) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < length; 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Antenna */
|
|
|
|
configSection = config_setting_get_member(configElement, "antenna");
|
|
|
|
if (configSection) {
|
2013-09-24 19:14:57 +02:00
|
|
|
radio->antenna.radioid = radio->radioid;
|
|
|
|
|
2013-09-22 22:28:59 +02:00
|
|
|
if (config_setting_lookup_bool(configSection, "diversity", &configBool) == CONFIG_TRUE) {
|
|
|
|
radio->antenna.diversity = (configBool ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_string(configSection, "combiner", &configString) == CONFIG_TRUE) {
|
|
|
|
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 != NULL) {
|
|
|
|
int count = config_setting_length(configItems);
|
|
|
|
if ((count > 0) && (count <= CAPWAP_ANTENNASELECTIONS_MAXLENGTH)) {
|
|
|
|
for (i = 0; i < count; 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-24 19:14:57 +02:00
|
|
|
/* 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) {
|
|
|
|
if ((configInt > 0) && (configInt < 65536)) {
|
|
|
|
radio->multidomaincapability.firstchannel = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configSection, "numberchannels", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt < 65536)) {
|
|
|
|
radio->multidomaincapability.numberchannels = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configSection, "maxtxpower", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt >= 0) && (configInt < 65536)) {
|
|
|
|
radio->multidomaincapability.maxtxpowerlevel = (uint16_t)configInt;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MAC Operation */
|
|
|
|
radio->macoperation.radioid = radio->radioid;
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "rtsthreshold", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt <= 2347)) {
|
|
|
|
radio->macoperation.rtsthreshold = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "shortretry", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 1) && (configInt < 256)) {
|
|
|
|
radio->macoperation.shortretry = (uint8_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "longretry", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 1) && (configInt < 256)) {
|
|
|
|
radio->macoperation.longretry = (uint8_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "fragmentationthreshold", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt >= 256) && (configInt <= 2346)) {
|
|
|
|
radio->macoperation.fragthreshold = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "txmsdulifetime", &configInt) == CONFIG_TRUE) {
|
|
|
|
if (configInt > 0) {
|
|
|
|
radio->macoperation.txmsdulifetime = (uint32_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "rxmsdulifetime", &configInt) == CONFIG_TRUE) {
|
|
|
|
if (configInt > 0) {
|
|
|
|
radio->macoperation.rxmsdulifetime = (uint32_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Supported rate */
|
|
|
|
radio->supportedrates.radioid = radio->radioid;
|
|
|
|
|
|
|
|
configItems = config_setting_get_member(configElement, "supportedrates");
|
|
|
|
if (configItems != NULL) {
|
|
|
|
int count = config_setting_length(configItems);
|
|
|
|
if ((count >= CAPWAP_SUPPORTEDRATES_MINLENGTH) && (count <= CAPWAP_SUPPORTEDRATES_MAXLENGTH)) {
|
|
|
|
radio->supportedrates.supportedratescount = (uint8_t)count;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
int value = config_setting_get_int_elem(configItems, i);
|
|
|
|
if ((value >= 2) && (value <= 127)) {
|
|
|
|
radio->supportedrates.supportedrates[i] = (uint8_t)value;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-25 21:22:09 +02:00
|
|
|
/* 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) {
|
|
|
|
if ((configInt >= 0) && (configInt <= 10000)) {
|
|
|
|
radio->txpower.currenttxpower = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-30 17:37:34 +02:00
|
|
|
configItems = config_setting_get_member(configSection, "supported");
|
2013-09-25 21:22:09 +02:00
|
|
|
if (configItems != NULL) {
|
|
|
|
int count = config_setting_length(configItems);
|
|
|
|
if ((count > 0) && (count <= CAPWAP_TXPOWERLEVEL_MAXLENGTH)) {
|
|
|
|
radio->txpowerlevel.radioid = radio->radioid;
|
|
|
|
radio->txpowerlevel.numlevels = (uint8_t)count;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
int value = config_setting_get_int_elem(configItems, i);
|
|
|
|
if ((configInt >= 0) && (configInt <= 10000)) {
|
|
|
|
radio->txpowerlevel.powerlevel[i] = (uint8_t)value;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-24 19:14:57 +02:00
|
|
|
/* WTP Radio Configuration */
|
|
|
|
radio->radioconfig.radioid = radio->radioid;
|
|
|
|
|
|
|
|
if (config_setting_lookup_bool(configElement, "shortpreamble", &configBool) == CONFIG_TRUE) {
|
|
|
|
radio->radioconfig.shortpreamble = (configBool ? CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_ENABLE : CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_DISABLE);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "maxbssid", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt <= 16)) {
|
|
|
|
radio->radioconfig.maxbssid = (uint8_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_setting_lookup_string(configElement, "bssprefixname", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) < IFNAMSIZ) {
|
|
|
|
strcpy(radio->wlanprefix, configString);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-24 19:14:57 +02:00
|
|
|
if (config_setting_lookup_int(configElement, "dtimperiod", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt < 256)) {
|
|
|
|
radio->radioconfig.dtimperiod = (uint8_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_int(configElement, "beaconperiod", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt < 65536)) {
|
|
|
|
radio->radioconfig.beaconperiod = (uint16_t)configInt;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_setting_lookup_string(configElement, "country", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) == 2) {
|
|
|
|
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)' ';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-22 22:28:59 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Parsing configuration */
|
|
|
|
static int wtp_parsing_configuration_1_0(config_t* config) {
|
|
|
|
int i;
|
2014-02-08 18:03:38 +01:00
|
|
|
int configBool;
|
|
|
|
LIBCONFIG_LOOKUP_INT_ARG configInt;
|
2013-05-01 14:52:55 +02:00
|
|
|
const char* configString;
|
|
|
|
config_setting_t* configSetting;
|
|
|
|
|
|
|
|
/* Logging configuration */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "logging.enable", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (!configBool) {
|
2013-05-01 14:52:55 +02:00
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_NONE);
|
|
|
|
capwap_logging_disable_allinterface();
|
|
|
|
} else {
|
|
|
|
if (config_lookup_string(config, "logging.level", &configString) == CONFIG_TRUE) {
|
|
|
|
if (!strcmp(configString, "fatal")) {
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_FATAL);
|
|
|
|
} else if (!strcmp(configString, "error")) {
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR);
|
|
|
|
} else if (!strcmp(configString, "warning")) {
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_WARNING);
|
|
|
|
} else if (!strcmp(configString, "info")) {
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_INFO);
|
|
|
|
} else if (!strcmp(configString, "debug")) {
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_DEBUG);
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("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);
|
|
|
|
|
2013-06-16 12:09:57 +02:00
|
|
|
/* Disable output interface */
|
2013-05-01 14:52:55 +02:00
|
|
|
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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown logging.output value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-16 12:09:57 +02:00
|
|
|
/* Set running mode */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.standalone", &configBool) == CONFIG_TRUE) {
|
|
|
|
g_wtp.standalone = ((configBool != 0) ? 1 : 0);
|
2013-06-16 12:09:57 +02:00
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Set name of WTP */
|
|
|
|
if (config_lookup_string(config, "application.name", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) > CAPWAP_WTPNAME_MAXLENGTH) {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.name string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-09 17:41:52 +02:00
|
|
|
capwap_free(g_wtp.name.name);
|
|
|
|
g_wtp.name.name = (uint8_t*)capwap_duplicate_string(configString);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set location of WTP */
|
|
|
|
if (config_lookup_string(config, "application.location", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) > CAPWAP_LOCATION_MAXLENGTH) {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.location string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-09 17:41:52 +02:00
|
|
|
capwap_free(g_wtp.location.value);
|
|
|
|
g_wtp.location.value = (uint8_t*)capwap_duplicate_string(configString);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.binding value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-03 22:28:06 +02:00
|
|
|
/* Initialize binding */
|
|
|
|
switch (g_wtp.binding) {
|
|
|
|
case CAPWAP_WIRELESS_BINDING_NONE: {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CAPWAP_WIRELESS_BINDING_IEEE80211: {
|
|
|
|
/* Initialize wifi binding driver */
|
|
|
|
capwap_logging_info("Initializing wifi binding engine");
|
2014-03-23 20:42:59 +01:00
|
|
|
if (wifi_driver_init(g_wtp.timeout)) {
|
2013-05-03 22:28:06 +02:00
|
|
|
capwap_logging_fatal("Unable initialize wifi binding engine");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
capwap_logging_fatal("Unable initialize unknown binding engine: %hu", g_wtp.binding);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Set tunnelmode of WTP */
|
|
|
|
if (config_lookup(config, "application.tunnelmode") != NULL) {
|
|
|
|
g_wtp.mactunnel.mode = 0;
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.tunnelmode.nativeframe", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
g_wtp.mactunnel.mode |= CAPWAP_WTP_NATIVE_FRAME_TUNNEL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.tunnelmode.ethframe", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
g_wtp.mactunnel.mode |= CAPWAP_WTP_8023_FRAME_TUNNEL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.tunnelmode.localbridging", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set mactype of WTP */
|
|
|
|
if (config_lookup_string(config, "application.mactype", &configString) == CONFIG_TRUE) {
|
|
|
|
if (!strcmp(configString, "localmac")) {
|
|
|
|
g_wtp.mactype.type = CAPWAP_LOCALMAC;
|
|
|
|
} else if (!strcmp(configString, "splitmac")) {
|
|
|
|
g_wtp.mactype.type = CAPWAP_SPLITMAC;
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.mactype value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set VendorID Boardinfo of WTP */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_int(config, "application.boardinfo.idvendor", &configInt) == CONFIG_TRUE) {
|
|
|
|
g_wtp.boarddata.vendor = (unsigned long)configInt;
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set Element Boardinfo of WTP */
|
|
|
|
configSetting = config_lookup(config, "application.boardinfo.element");
|
|
|
|
if (configSetting != NULL) {
|
|
|
|
int count = config_setting_length(configSetting);
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
|
|
|
|
if (configElement != NULL) {
|
|
|
|
const char* configName;
|
|
|
|
if (config_setting_lookup_string(configElement, "name", &configName) == CONFIG_TRUE) {
|
|
|
|
const char* configValue;
|
|
|
|
if (config_setting_lookup_string(configElement, "value", &configValue) == CONFIG_TRUE) {
|
|
|
|
int lengthValue = strlen(configValue);
|
|
|
|
if (lengthValue < CAPWAP_BOARD_SUBELEMENT_MAXDATA) {
|
|
|
|
struct capwap_wtpboarddata_board_subelement* element = (struct capwap_wtpboarddata_board_subelement*)capwap_array_get_item_pointer(g_wtp.boarddata.boardsubelement, g_wtp.boarddata.boardsubelement->count);
|
|
|
|
|
|
|
|
if (!strcmp(configName, "model")) {
|
|
|
|
element->type = CAPWAP_BOARD_SUBELEMENT_MODELNUMBER;
|
|
|
|
element->length = lengthValue;
|
2013-06-09 17:41:52 +02:00
|
|
|
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else if (!strcmp(configName, "serial")) {
|
|
|
|
element->type = CAPWAP_BOARD_SUBELEMENT_SERIALNUMBER;
|
|
|
|
element->length = lengthValue;
|
2013-06-09 17:41:52 +02:00
|
|
|
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else if (!strcmp(configName, "id")) {
|
|
|
|
element->type = CAPWAP_BOARD_SUBELEMENT_ID;
|
|
|
|
element->length = lengthValue;
|
2013-06-09 17:41:52 +02:00
|
|
|
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else if (!strcmp(configName, "revision")) {
|
|
|
|
element->type = CAPWAP_BOARD_SUBELEMENT_REVISION;
|
|
|
|
element->length = lengthValue;
|
2013-06-09 17:41:52 +02:00
|
|
|
element->data = (uint8_t*)capwap_clone((void*)configValue, lengthValue);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else if (!strcmp(configName, "macaddress")) {
|
|
|
|
const char* configType;
|
|
|
|
if (config_setting_lookup_string(configElement, "type", &configType) == CONFIG_TRUE) {
|
|
|
|
if (!strcmp(configType, "interface")) {
|
2013-06-09 17:41:52 +02:00
|
|
|
char macaddress[MACADDRESS_EUI64_LENGTH];
|
|
|
|
|
|
|
|
/* Retrieve macaddress */
|
2013-05-01 14:52:55 +02:00
|
|
|
element->type = CAPWAP_BOARD_SUBELEMENT_MACADDRESS;
|
2013-06-09 17:41:52 +02:00
|
|
|
element->length = capwap_get_macaddress_from_interface(configValue, macaddress);
|
|
|
|
if (!element->length || ((element->length != MACADDRESS_EUI64_LENGTH) && (element->length != MACADDRESS_EUI48_LENGTH))) {
|
2013-05-01 14:52:55 +02:00
|
|
|
capwap_logging_error("Invalid configuration file, unable found macaddress of interface: '%s'", configValue);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-06-09 17:41:52 +02:00
|
|
|
|
|
|
|
element->data = (uint8_t*)capwap_clone((void*)macaddress, element->length);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.boardinfo.element.type value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.boardinfo.element.type not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.boardinfo.element.name value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.boardinfo.element.value string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.boardinfo.element.value not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.boardinfo.element.name not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-20 23:14:34 +01:00
|
|
|
/* 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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, wlan.prefix string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-22 22:28:59 +02:00
|
|
|
/* Set Radio WTP */
|
|
|
|
configSetting = config_lookup(config, "application.radio");
|
2013-05-01 14:52:55 +02:00
|
|
|
if (configSetting != NULL) {
|
2013-12-20 23:14:34 +01:00
|
|
|
struct wtp_radio* radio;
|
2014-01-10 13:25:28 +01:00
|
|
|
const struct wifi_capability* capability;
|
2013-05-01 14:52:55 +02:00
|
|
|
int count = config_setting_length(configSetting);
|
|
|
|
|
|
|
|
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
|
|
|
for (i = 0; i < count; i++) {
|
2013-07-27 22:46:17 +02:00
|
|
|
if (!IS_VALID_RADIOID(g_wtp.radios->count + 1)) {
|
|
|
|
capwap_logging_error("Exceeded max number of radio device");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2013-05-01 14:52:55 +02:00
|
|
|
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
|
|
|
|
if (configElement != NULL) {
|
|
|
|
if (config_setting_lookup_string(configElement, "device", &configString) == CONFIG_TRUE) {
|
|
|
|
if (*configString && (strlen(configString) < IFNAMSIZ)) {
|
2013-09-22 22:28:59 +02:00
|
|
|
/* Create new radio device */
|
2013-12-20 23:14:34 +01:00
|
|
|
radio = wtp_radio_create_phy();
|
2013-09-22 22:28:59 +02:00
|
|
|
strcpy(radio->device, configString);
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_setting_lookup_bool(configElement, "enabled", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool) {
|
2013-09-22 22:28:59 +02:00
|
|
|
/* Retrieve radio capability */
|
|
|
|
if (wtp_parsing_radio_configuration(configElement, radio)) {
|
|
|
|
/* Initialize radio device */
|
|
|
|
if (config_setting_lookup_string(configElement, "driver", &configString) == CONFIG_TRUE) {
|
|
|
|
if (*configString && (strlen(configString) < WIFI_DRIVER_NAME_SIZE)) {
|
2014-02-08 18:03:38 +01:00
|
|
|
radio->devicehandle = wifi_device_connect(radio->device, configString);
|
|
|
|
if (radio->devicehandle) {
|
2013-09-22 22:28:59 +02:00
|
|
|
radio->status = WTP_RADIO_ENABLED;
|
|
|
|
capwap_logging_info("Register radioid %d with radio device: %s - %s", radio->radioid, radio->device, configString);
|
|
|
|
|
|
|
|
/* Update radio capability with device query */
|
2014-02-08 18:03:38 +01:00
|
|
|
capability = wifi_device_getcapability(radio->devicehandle);
|
2013-09-22 22:28:59 +02:00
|
|
|
if (capability) {
|
2014-02-08 18:03:38 +01:00
|
|
|
uint8_t bssid;
|
|
|
|
char wlanname[IFNAMSIZ];
|
|
|
|
struct capwap_list_item* itemwlan;
|
|
|
|
struct wtp_radio_wlanpool* wlanpool;
|
|
|
|
|
|
|
|
/* Create interface */
|
|
|
|
for (bssid = 0; bssid < radio->radioconfig.maxbssid; bssid++) {
|
|
|
|
sprintf(wlanname, "%s%02d.%02d", radio->wlanprefix, (int)radio->radioid, (int)bssid + 1);
|
|
|
|
if (wifi_iface_index(wlanname)) {
|
|
|
|
capwap_logging_error("interface %s already exists", wlanname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
|
|
itemwlan = capwap_itemlist_create(sizeof(struct wtp_radio_wlanpool));
|
|
|
|
wlanpool = (struct wtp_radio_wlanpool*)itemwlan->item;
|
|
|
|
wlanpool->radio = radio;
|
|
|
|
wlanpool->wlanhandle = wifi_wlan_create(radio->devicehandle, wlanname);
|
|
|
|
if (!wlanpool->wlanhandle) {
|
|
|
|
capwap_logging_error("Unable to create interface: %s", wlanname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Appent to wlan pool */
|
|
|
|
capwap_logging_debug("Created wlan interface: %s", wlanname);
|
|
|
|
capwap_itemlist_insert_after(radio->wlanpool, NULL, itemwlan);
|
|
|
|
}
|
2013-09-22 22:28:59 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
radio->status = WTP_RADIO_HWFAILURE;
|
|
|
|
capwap_logging_warning("Unable to register radio device: %s - %s", radio->device, configString);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-03 22:28:06 +02:00
|
|
|
} else {
|
2013-09-22 22:28:59 +02:00
|
|
|
capwap_logging_error("Invalid configuration file, application.radio");
|
|
|
|
return 0;
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-09-22 22:28:59 +02:00
|
|
|
capwap_logging_error("Invalid configuration file, application.radio.device string length exceeded");
|
2013-05-01 14:52:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
2013-09-22 22:28:59 +02:00
|
|
|
capwap_logging_error("Invalid configuration file, element application.radio.device not found");
|
2013-05-01 14:52:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update radio status */
|
|
|
|
g_wtp.descriptor.maxradios = g_wtp.radios->count;
|
|
|
|
g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 {
|
|
|
|
capwap_logging_error("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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.descriptor.encryption not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set info descriptor of WTP */
|
|
|
|
configSetting = config_lookup(config, "application.descriptor.info");
|
|
|
|
if (configSetting != NULL) {
|
|
|
|
int count = config_setting_length(configSetting);
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
|
|
|
|
if (configElement != NULL) {
|
2014-02-08 18:03:38 +01:00
|
|
|
LIBCONFIG_LOOKUP_INT_ARG configVendor;
|
2013-05-01 14:52:55 +02:00
|
|
|
if (config_setting_lookup_int(configElement, "idvendor", &configVendor) == CONFIG_TRUE) {
|
|
|
|
const char* configType;
|
|
|
|
if (config_setting_lookup_string(configElement, "type", &configType) == CONFIG_TRUE) {
|
|
|
|
const char* configValue;
|
|
|
|
if (config_setting_lookup_string(configElement, "value", &configValue) == CONFIG_TRUE) {
|
|
|
|
int lengthValue = strlen(configValue);
|
|
|
|
if (lengthValue < CAPWAP_WTPDESC_SUBELEMENT_MAXDATA) {
|
|
|
|
unsigned short type;
|
|
|
|
struct capwap_wtpdescriptor_desc_subelement* desc;
|
|
|
|
|
|
|
|
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 {
|
|
|
|
capwap_logging_error("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;
|
2013-08-19 22:28:41 +02:00
|
|
|
desc->data = (uint8_t*)capwap_duplicate_string(configValue);
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.descriptor.info.value string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.descriptor.info.value not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.descriptor.info.type not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, element application.descriptor.info.idvendor not found");
|
|
|
|
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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.ecn value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set Timer of WTP */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_int(config, "application.timer.statistics", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt < 65536)) {
|
|
|
|
g_wtp.statisticstimer.timer = (unsigned short)configInt;
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, invalid application.timer.statistics value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set DTLS of WTP */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.dtls.enable", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
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;
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.dtls.dtlspolicy.cleardatachannel", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.dtls.dtlspolicy.dtlsdatachannel", &configBool) == CONFIG_TRUE) {
|
|
|
|
if (configBool != 0) {
|
2013-05-01 14:52:55 +02:00
|
|
|
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 {
|
|
|
|
capwap_logging_error("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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-27 23:10:49 +02:00
|
|
|
/* */
|
2013-05-01 14:52:55 +02:00
|
|
|
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);
|
|
|
|
}
|
2013-05-27 23:10:49 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
if (dtlsparam.cert.filecert) {
|
|
|
|
capwap_free(dtlsparam.cert.filecert);
|
|
|
|
}
|
2013-05-27 23:10:49 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
if (dtlsparam.cert.filekey) {
|
|
|
|
capwap_free(dtlsparam.cert.filekey);
|
|
|
|
}
|
2013-05-27 23:10:49 +02:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2013-05-27 23:10:49 +02:00
|
|
|
if (config_lookup_string(config, "application.dtls.presharedkey.pskkey", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) > 0) {
|
|
|
|
dtlsparam.presharedkey.pskkey = capwap_duplicate_string(configString);
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
2013-05-27 23:10:49 +02:00
|
|
|
|
|
|
|
/* */
|
|
|
|
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;
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set interface binding of WTP */
|
|
|
|
if (config_lookup_string(config, "application.network.binding", &configString) == CONFIG_TRUE) {
|
|
|
|
if (strlen(configString) > (IFNAMSIZ - 1)) {
|
|
|
|
capwap_logging_error("Invalid configuration file, application.network.binding string length exceeded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-10 21:58:23 +02:00
|
|
|
strcpy(g_wtp.net.bindiface, configString);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set mtu of WTP */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_int(config, "application.network.mtu", &configInt) == CONFIG_TRUE) {
|
|
|
|
if ((configInt > 0) && (configInt < 65536)) {
|
|
|
|
g_wtp.mtu = (unsigned short)configInt;
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("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 {
|
|
|
|
capwap_logging_error("Invalid configuration file, unknown application.network.transport value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set search discovery of WTP */
|
2014-02-08 18:03:38 +01:00
|
|
|
if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) {
|
|
|
|
g_wtp.acdiscoveryrequest = (configBool ? 1 : 0);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set discovery host of WTP */
|
|
|
|
configSetting = config_lookup(config, "application.acdiscovery.host");
|
|
|
|
if (configSetting != NULL) {
|
|
|
|
int count = config_setting_length(configSetting);
|
2014-09-10 21:58:23 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
const char* address = config_setting_get_string_elem(configSetting, i);
|
|
|
|
if (address != NULL) {
|
2014-09-10 21:58:23 +02:00
|
|
|
union sockaddr_capwap acaddr;
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Parsing address */
|
|
|
|
if (capwap_address_from_string(address, &acaddr)) {
|
|
|
|
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
|
|
|
|
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
|
|
|
|
}
|
|
|
|
|
2014-09-10 21:58:23 +02:00
|
|
|
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &acaddr, sizeof(union sockaddr_capwap));
|
2013-06-09 17:41:52 +02:00
|
|
|
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_STATIC;
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, invalid application.acdiscovery.host value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set preferred ac of WTP */
|
|
|
|
configSetting = config_lookup(config, "application.acprefered.host");
|
|
|
|
if (configSetting != NULL) {
|
|
|
|
int count = config_setting_length(configSetting);
|
2014-09-10 21:58:23 +02:00
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
const char* address = config_setting_get_string_elem(configSetting, i);
|
|
|
|
if (address != NULL) {
|
2014-09-10 21:58:23 +02:00
|
|
|
union sockaddr_capwap acaddr;
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* Parsing address */
|
|
|
|
if (capwap_address_from_string(address, &acaddr)) {
|
|
|
|
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
|
|
|
|
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
|
|
|
|
}
|
|
|
|
|
2014-09-10 21:58:23 +02:00
|
|
|
memcpy(capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedarray->count), &acaddr, sizeof(union sockaddr_capwap));
|
2013-05-01 14:52:55 +02:00
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, invalid application.acprefered.host value");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
capwap_logging_error("Invalid configuration file, '%s' is not supported", configString);
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid configuration file, unable to found version tag");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load configuration */
|
|
|
|
static int wtp_load_configuration(int argc, char **argv) {
|
|
|
|
int c;
|
|
|
|
int result = 0;
|
|
|
|
config_t config;
|
|
|
|
|
|
|
|
ASSERT(argc >= 0);
|
|
|
|
ASSERT(argv != NULL);
|
|
|
|
|
|
|
|
/* Parsing command line */
|
|
|
|
opterr = 0;
|
|
|
|
while ((c = getopt(argc, argv, "hc:")) != -1) {
|
|
|
|
switch (c) {
|
|
|
|
case 'h': {
|
|
|
|
wtp_print_usage();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'c': {
|
|
|
|
if (strlen(optarg) < sizeof(g_configurationfile)) {
|
|
|
|
strcpy(g_configurationfile, optarg);
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Invalid -%c argument", optopt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case '?': {
|
|
|
|
if (optopt == 'c') {
|
|
|
|
capwap_logging_error("Option -%c requires an argument", optopt);
|
|
|
|
} else {
|
|
|
|
capwap_logging_error("Unknown option character `\\x%x'", optopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
wtp_print_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Init libconfig */
|
|
|
|
config_init(&config);
|
|
|
|
|
|
|
|
/* Load configuration */
|
|
|
|
if (config_read_file(&config, g_configurationfile) == CONFIG_TRUE) {
|
|
|
|
result = wtp_parsing_configuration(&config);
|
|
|
|
} else {
|
|
|
|
result = -1;
|
|
|
|
capwap_logging_error("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) {
|
2014-09-10 21:58:23 +02:00
|
|
|
/* If not set try IPv6 */
|
|
|
|
if (g_wtp.net.localaddr.ss.ss_family == AF_UNSPEC) {
|
|
|
|
g_wtp.net.localaddr.ss.ss_family = AF_INET6;
|
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* If request add default acdiscovery */
|
|
|
|
if (!g_wtp.acdiscoveryarray->count) {
|
2014-09-10 21:58:23 +02:00
|
|
|
wtp_add_default_acaddress();
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
2014-09-10 21:58:23 +02:00
|
|
|
|
|
|
|
/* Bind control address */
|
|
|
|
if (capwap_bind_sockets(&g_wtp.net)) {
|
|
|
|
capwap_logging_fatal("Cannot bind control address");
|
|
|
|
return WTP_ERROR_NETWORK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bind data address */
|
|
|
|
if (wtp_kmod_bind(g_wtp.net.localaddr.ss.ss_family)) {
|
|
|
|
capwap_logging_fatal("Cannot bind data address");
|
2013-05-01 14:52:55 +02:00
|
|
|
return WTP_ERROR_NETWORK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CAPWAP_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
/* */
|
|
|
|
static void wtp_wait_radio_ready(void) {
|
|
|
|
int index;
|
|
|
|
struct wtp_fds fds;
|
|
|
|
|
|
|
|
/* Get only radio file descriptor */
|
|
|
|
memset(&fds, 0, sizeof(struct wtp_fds));
|
2014-06-07 22:37:19 +02:00
|
|
|
wtp_dfa_update_fdspool(&fds);
|
|
|
|
if (fds.wifieventscount > 0) {
|
|
|
|
ASSERT(fds.fdsnetworkcount == 0);
|
|
|
|
ASSERT(fds.kmodeventscount == 0);
|
2014-02-08 18:03:38 +01:00
|
|
|
|
2014-06-07 22:37:19 +02:00
|
|
|
for (;;) {
|
|
|
|
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RADIO_INITIALIZATION_INTERVAL, NULL, NULL, NULL);
|
2014-02-08 18:03:38 +01:00
|
|
|
|
2014-06-07 22:37:19 +02:00
|
|
|
/* Wait packet */
|
|
|
|
index = capwap_wait_recvready(fds.fdspoll, fds.fdstotalcount, g_wtp.timeout);
|
|
|
|
if (index < 0) {
|
|
|
|
break;
|
|
|
|
} else if (!fds.wifievents[index].event_handler) {
|
|
|
|
break;
|
|
|
|
}
|
2014-02-08 18:03:38 +01:00
|
|
|
|
2014-06-07 22:37:19 +02:00
|
|
|
fds.wifievents[index].event_handler(fds.fdspoll[index].fd, fds.wifievents[index].params, fds.wifievents[index].paramscount);
|
|
|
|
}
|
2014-02-08 18:03:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2014-06-07 22:37:19 +02:00
|
|
|
wtp_dfa_free_fdspool(&fds);
|
2014-03-02 19:31:27 +01:00
|
|
|
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
|
2014-02-08 18:03:38 +01:00
|
|
|
}
|
|
|
|
|
2013-05-01 14:52:55 +02:00
|
|
|
/* */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Init logging */
|
|
|
|
capwap_logging_init();
|
|
|
|
capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR);
|
|
|
|
capwap_logging_enable_console(1);
|
|
|
|
|
|
|
|
/* Init capwap */
|
|
|
|
if (geteuid() != 0) {
|
|
|
|
capwap_logging_fatal("Request root privileges");
|
2013-05-01 21:33:54 +02:00
|
|
|
result = CAPWAP_REQUEST_ROOT;
|
|
|
|
} else {
|
|
|
|
/* Init random generator */
|
|
|
|
capwap_init_rand();
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2013-05-01 21:33:54 +02:00
|
|
|
/* Init crypt */
|
2014-05-15 21:43:21 +02:00
|
|
|
if (capwap_crypt_init()) {
|
2013-05-01 21:33:54 +02:00
|
|
|
result = CAPWAP_CRYPT_ERROR;
|
|
|
|
capwap_logging_fatal("Error to init crypt engine");
|
|
|
|
} else {
|
2013-06-16 12:09:57 +02:00
|
|
|
/* Init WTP */
|
2013-05-01 21:33:54 +02:00
|
|
|
if (!wtp_init()) {
|
|
|
|
result = WTP_ERROR_SYSTEM_FAILER;
|
|
|
|
capwap_logging_fatal("Error to init WTP engine");
|
|
|
|
} else {
|
|
|
|
/* Read configuration file */
|
|
|
|
value = wtp_load_configuration(argc, argv);
|
|
|
|
if (value < 0) {
|
|
|
|
result = WTP_ERROR_LOAD_CONFIGURATION;
|
|
|
|
capwap_logging_fatal("Error to load configuration");
|
|
|
|
} else if (value > 0) {
|
2013-06-16 12:09:57 +02:00
|
|
|
if (!g_wtp.standalone) {
|
|
|
|
capwap_daemon();
|
|
|
|
|
|
|
|
/* Console logging is disabled in daemon mode */
|
|
|
|
capwap_logging_disable_console();
|
|
|
|
capwap_logging_info("Running WTP in daemon mode");
|
|
|
|
}
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
/* Wait the initialization of radio interfaces */
|
|
|
|
capwap_logging_info("Wait the initialization of radio interfaces");
|
|
|
|
wtp_wait_radio_ready();
|
|
|
|
|
2014-06-01 16:32:30 +02:00
|
|
|
/* Connect WTP with kernel module */
|
2014-09-10 21:58:23 +02:00
|
|
|
if (!wtp_kmod_init()) {
|
|
|
|
capwap_logging_info("SmartCAPWAP kernel module connected");
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2014-06-01 16:32:30 +02:00
|
|
|
/* */
|
|
|
|
capwap_logging_info("Startup WTP");
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2014-06-01 16:32:30 +02:00
|
|
|
/* Complete configuration WTP */
|
|
|
|
result = wtp_configure();
|
|
|
|
if (result == CAPWAP_SUCCESSFUL) {
|
|
|
|
/* Running WTP */
|
|
|
|
result = wtp_dfa_running();
|
|
|
|
|
2014-09-10 21:58:23 +02:00
|
|
|
/* Close sockets */
|
2014-06-01 16:32:30 +02:00
|
|
|
capwap_close_sockets(&g_wtp.net);
|
|
|
|
}
|
2013-05-01 21:33:54 +02:00
|
|
|
|
2014-06-01 16:32:30 +02:00
|
|
|
/* Disconnect kernel module */
|
2014-06-07 22:37:19 +02:00
|
|
|
wtp_kmod_free();
|
2014-06-01 16:32:30 +02:00
|
|
|
|
|
|
|
/* */
|
|
|
|
capwap_logging_info("Terminate WTP");
|
|
|
|
} else {
|
|
|
|
capwap_logging_fatal("Unable to connect with kernel module");
|
|
|
|
}
|
2013-05-01 21:33:54 +02:00
|
|
|
|
2013-12-20 23:14:34 +01:00
|
|
|
/* Close radio */
|
|
|
|
wtp_radio_close();
|
|
|
|
|
2013-05-03 22:28:06 +02:00
|
|
|
/* Free binding */
|
2013-12-20 23:14:34 +01:00
|
|
|
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
|
|
|
capwap_logging_info("Free wifi binding engine");
|
|
|
|
wifi_driver_free();
|
2013-05-01 21:33:54 +02:00
|
|
|
}
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2013-05-01 21:33:54 +02:00
|
|
|
/* Free memory */
|
|
|
|
wtp_destroy();
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2013-05-01 21:33:54 +02:00
|
|
|
/* Free crypt */
|
|
|
|
capwap_crypt_free();
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2013-05-01 21:33:54 +02:00
|
|
|
/* Check memory leak */
|
|
|
|
if (capwap_check_memory_leak(1)) {
|
|
|
|
if (result == CAPWAP_SUCCESSFUL) {
|
|
|
|
result = WTP_ERROR_MEMORY_LEAK;
|
|
|
|
}
|
|
|
|
}
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close logging */
|
|
|
|
capwap_logging_close();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|