First commit
This commit is contained in:
963
src/wtp/wtp.c
Normal file
963
src/wtp/wtp.c
Normal file
@ -0,0 +1,963 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_network.h"
|
||||
#include "capwap_protocol.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_array.h"
|
||||
#include "capwap_element.h"
|
||||
#include "capwap_dtls.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
struct wtp_t g_wtp;
|
||||
|
||||
/* Local param */
|
||||
#define WTP_STANDARD_NAME "Unknown WTP"
|
||||
#define WTP_STANDARD_LOCATION "Unknown Location"
|
||||
|
||||
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 name */
|
||||
strcpy(g_wtp.name.name, WTP_STANDARD_NAME);
|
||||
strcpy(g_wtp.location.value, WTP_STANDARD_LOCATION);
|
||||
|
||||
/* State machine */
|
||||
g_wtp.dfa.state = CAPWAP_START_STATE;
|
||||
g_wtp.dfa.rfcMaxDiscoveryInterval = WTP_DEFAULT_DISCOVERY_INTERVAL;
|
||||
g_wtp.dfa.rfcMaxDiscoveries = WTP_DEFAULT_DISCOVERY_COUNT;
|
||||
g_wtp.dfa.rfcSilentInterval = WTP_DEFAULT_SILENT_INTERVAL;
|
||||
g_wtp.dfa.rfcRetransmitInterval = WTP_DEFAULT_RETRANSMIT_INTERVAL;
|
||||
g_wtp.dfa.rfcMaxRetransmit = WTP_MAX_RETRANSMIT;
|
||||
g_wtp.dfa.rfcWaitDTLS = WTP_DEFAULT_WAITDTLS_INTERVAL;
|
||||
g_wtp.dfa.rfcDataChannelKeepAlive = WTP_DEFAULT_DATACHANNEL_KEEPALIVE;
|
||||
g_wtp.dfa.rfcDataChannelDeadInterval = WTP_DEFAULT_DATACHANNEL_KEEPALIVEDEAD;
|
||||
g_wtp.dfa.rfcEchoInterval = WTP_DEFAULT_ECHO_INTERVAL;
|
||||
g_wtp.dfa.rfcDTLSSessionDelete = WTP_DEFAULT_DTLS_SESSION_DELETE;
|
||||
g_wtp.dfa.rfcMaxFailedDTLSSessionRetry = WTP_DEFAULT_FAILED_DTLS_SESSION_RETRY;
|
||||
|
||||
/* Socket */
|
||||
capwap_network_init(&g_wtp.net);
|
||||
|
||||
/* Standard configuration */
|
||||
g_wtp.boarddata.boardsubelement = capwap_array_create(sizeof(struct capwap_wtpboarddata_board_subelement), 0);
|
||||
g_wtp.descriptor.encryptsubelement = capwap_array_create(sizeof(struct capwap_wtpdescriptor_encrypt_subelement), 0);
|
||||
g_wtp.descriptor.descsubelement = capwap_array_create(sizeof(struct capwap_wtpdescriptor_desc_subelement), 0);
|
||||
|
||||
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_DEFAULT_STATISTICSTIMER_INTERVAL;
|
||||
|
||||
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.mtu = CAPWAP_MTU_DEFAULT;
|
||||
g_wtp.requestfragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
|
||||
g_wtp.responsefragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
|
||||
|
||||
/* AC information */
|
||||
g_wtp.discoverytype.type = CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_UNKNOWN;
|
||||
g_wtp.acdiscoveryrequest = 1;
|
||||
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(struct sockaddr_storage), 0);
|
||||
g_wtp.acpreferedarray = capwap_array_create(sizeof(struct sockaddr_storage), 0);
|
||||
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0);
|
||||
|
||||
/* Radios */
|
||||
g_wtp.radios = capwap_array_create(sizeof(struct wtp_radio), 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Destroy WTP */
|
||||
static void wtp_destroy(void) {
|
||||
/* Dtls */
|
||||
capwap_crypt_freecontext(&g_wtp.dtlscontext);
|
||||
|
||||
/* Free standard configuration */
|
||||
capwap_array_free(g_wtp.descriptor.encryptsubelement);
|
||||
capwap_array_free(g_wtp.descriptor.descsubelement);
|
||||
capwap_array_free(g_wtp.boarddata.boardsubelement);
|
||||
|
||||
/* Free fragments packet */
|
||||
capwap_fragment_free(g_wtp.requestfragmentpacket);
|
||||
capwap_fragment_free(g_wtp.responsefragmentpacket);
|
||||
capwap_array_free(g_wtp.requestfragmentpacket);
|
||||
capwap_array_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 radios */
|
||||
capwap_array_free(g_wtp.radios);
|
||||
}
|
||||
|
||||
/* Save AC address */
|
||||
static int wtp_add_acaddress(struct sockaddr_storage* source, struct capwap_array* array) {
|
||||
ASSERT(source != NULL);
|
||||
ASSERT(array != NULL);
|
||||
|
||||
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == source->ss_family)) {
|
||||
struct sockaddr_storage* destaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(array, array->count);
|
||||
|
||||
/* Save address, if request, mapping IPv4 to IPv6 */
|
||||
if ((g_wtp.net.sock_family == AF_UNSPEC) && (source->ss_family == AF_INET) && !(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG)) {
|
||||
if (!capwap_ipv4_mapped_ipv6(source, destaddr)) {
|
||||
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
|
||||
}
|
||||
} else {
|
||||
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int wtp_add_default_acaddress() {
|
||||
struct sockaddr_storage address;
|
||||
struct sockaddr_in* addressv4 = (struct sockaddr_in*)&address;
|
||||
/*struct sockaddr_in6* addressv6 = (struct sockaddr_in6*)&address;*/
|
||||
|
||||
/* Broadcast IPv4 */
|
||||
addressv4->sin_family = AF_INET;
|
||||
addressv4->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
addressv4->sin_port = htons(CAPWAP_CONTROL_PORT);
|
||||
wtp_add_acaddress(&address, g_wtp.acdiscoveryarray);
|
||||
|
||||
/* Multicast IPv4 */
|
||||
/* TODO */
|
||||
|
||||
/* Multicast IPv6 */
|
||||
/* TODO */
|
||||
|
||||
return ((g_wtp.acdiscoveryarray->count > 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Help */
|
||||
static void wtp_print_usage(void) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* Parsing configuration */
|
||||
static int wtp_parsing_configuration_1_0(config_t* config) {
|
||||
int i;
|
||||
int configInt;
|
||||
int configIPv4;
|
||||
int configIPv6;
|
||||
long int configLongInt;
|
||||
const char* configString;
|
||||
config_setting_t* configSetting;
|
||||
|
||||
/* Logging configuration */
|
||||
if (config_lookup_bool(config, "logging.enable", &configInt) == CONFIG_TRUE) {
|
||||
if (!configInt) {
|
||||
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);
|
||||
|
||||
/* 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 {
|
||||
capwap_logging_error("Invalid configuration file, unknown logging.output value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
strcpy(g_wtp.name.name, configString);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
strcpy(g_wtp.location.value, 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 {
|
||||
capwap_logging_error("Invalid configuration file, unknown application.binding value");
|
||||
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", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 0) {
|
||||
g_wtp.mactunnel.mode |= CAPWAP_WTP_NATIVE_FRAME_TUNNEL;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_lookup_bool(config, "application.tunnelmode.ethframe", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 0) {
|
||||
g_wtp.mactunnel.mode |= CAPWAP_WTP_8023_FRAME_TUNNEL;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_lookup_bool(config, "application.tunnelmode.localbridging", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 0) {
|
||||
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 */
|
||||
if (config_lookup_int(config, "application.boardinfo.idvendor", &configLongInt) == CONFIG_TRUE) {
|
||||
g_wtp.boarddata.vendor = (unsigned long)configLongInt;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
strcpy(element->data, configValue);
|
||||
} else if (!strcmp(configName, "serial")) {
|
||||
element->type = CAPWAP_BOARD_SUBELEMENT_SERIALNUMBER;
|
||||
element->length = lengthValue;
|
||||
strcpy(element->data, configValue);
|
||||
} else if (!strcmp(configName, "id")) {
|
||||
element->type = CAPWAP_BOARD_SUBELEMENT_ID;
|
||||
element->length = lengthValue;
|
||||
strcpy(element->data, configValue);
|
||||
} else if (!strcmp(configName, "revision")) {
|
||||
element->type = CAPWAP_BOARD_SUBELEMENT_REVISION;
|
||||
element->length = lengthValue;
|
||||
strcpy(element->data, configValue);
|
||||
} else if (!strcmp(configName, "macaddress")) {
|
||||
const char* configType;
|
||||
if (config_setting_lookup_string(configElement, "type", &configType) == CONFIG_TRUE) {
|
||||
if (!strcmp(configType, "interface")) {
|
||||
element->type = CAPWAP_BOARD_SUBELEMENT_MACADDRESS;
|
||||
element->length = capwap_get_macaddress_from_interface(configValue, element->data);
|
||||
if (!element->length) {
|
||||
capwap_logging_error("Invalid configuration file, unable found macaddress of interface: '%s'", configValue);
|
||||
return 0;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set Radio descriptor of WTP */
|
||||
configSetting = config_lookup(config, "application.descriptor.radio");
|
||||
if (configSetting != NULL) {
|
||||
int count = config_setting_length(configSetting);
|
||||
|
||||
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
||||
for (i = 0; i < count; i++) {
|
||||
struct wtp_radio* radio;
|
||||
char radioname[IFNAMSIZ];
|
||||
unsigned char radiotype = 0;
|
||||
int radiostatus = WTP_RADIO_ENABLED;
|
||||
|
||||
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)) {
|
||||
strcpy(radioname, configString);
|
||||
if (config_setting_lookup_string(configElement, "type", &configString) == CONFIG_TRUE) {
|
||||
int length = strlen(configString);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
switch (configString[i]) {
|
||||
case 'a': {
|
||||
radiotype |= CAPWAP_RADIO_TYPE_80211A;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b': {
|
||||
radiotype |= CAPWAP_RADIO_TYPE_80211B;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g': {
|
||||
radiotype |= CAPWAP_RADIO_TYPE_80211G;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n': {
|
||||
radiotype |= CAPWAP_RADIO_TYPE_80211N;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
capwap_logging_error("Invalid configuration file, unknown application.descriptor.radio.type value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (radiotype != 0) {
|
||||
if (config_setting_lookup_string(configElement, "status", &configString) == CONFIG_TRUE) {
|
||||
if (!strcmp(configString, "enabled")) {
|
||||
radiostatus = WTP_RADIO_ENABLED;
|
||||
} else if (!strcmp(configString, "disabled")) {
|
||||
radiostatus = WTP_RADIO_DISABLED;
|
||||
} else if (!strcmp(configString, "hwfailure")) {
|
||||
radiostatus = WTP_RADIO_HWFAILURE;
|
||||
} else if (!strcmp(configString, "swfailure")) {
|
||||
radiostatus = WTP_RADIO_SWFAILURE;
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, unknown application.descriptor.radio.type value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create new radio device */
|
||||
radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, g_wtp.radios->count);
|
||||
strcpy(radio->device, radioname);
|
||||
radio->radioinformation.radioid = g_wtp.radios->count;
|
||||
radio->radioinformation.radiotype = radiotype;
|
||||
radio->status = radiostatus;
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, unknown application.descriptor.radio.type value");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, element application.descriptor.radio.type not found");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, application.descriptor.radio.device string length exceeded");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, element application.descriptor.radio.device not found");
|
||||
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) {
|
||||
long int configVendor;
|
||||
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;
|
||||
desc->length = lengthValue;
|
||||
strcpy(desc->data, configValue);
|
||||
} 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 */
|
||||
if (config_lookup_int(config, "application.timer.statistics", &configLongInt) == CONFIG_TRUE) {
|
||||
if ((configLongInt > 0) && (configLongInt < 65536)) {
|
||||
g_wtp.statisticstimer.timer = (unsigned short)configLongInt;
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, invalid application.timer.statistics value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set DTLS of WTP */
|
||||
if (config_lookup_bool(config, "application.dtls.enable", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 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", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 0) {
|
||||
g_wtp.validdtlsdatapolicy |= CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_lookup_bool(config, "application.dtls.dtlspolicy.dtlsdatachannel", &configInt) == CONFIG_TRUE) {
|
||||
if (configInt != 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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (config_lookup_string(config, "application.dtls.x509.privatekeypassword", &configString) == CONFIG_TRUE) {
|
||||
if (strlen(configString) > 0) {
|
||||
dtlsparam.cert.pwdprivatekey = 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);
|
||||
}
|
||||
|
||||
if (dtlsparam.cert.pwdprivatekey) {
|
||||
capwap_free(dtlsparam.cert.pwdprivatekey);
|
||||
}
|
||||
|
||||
if (!g_wtp.enabledtls) {
|
||||
return 0;
|
||||
}
|
||||
} else if (dtlsparam.mode == CAPWAP_DTLS_MODE_PRESHAREDKEY) {
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
strcpy(g_wtp.net.bind_interface, configString);
|
||||
}
|
||||
|
||||
/* Set mtu of WTP */
|
||||
if (config_lookup_int(config, "application.network.mtu", &configLongInt) == CONFIG_TRUE) {
|
||||
if ((configLongInt > 0) && (configLongInt < 65536)) {
|
||||
g_wtp.mtu = (unsigned short)configLongInt;
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, invalid application.network.mtu value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set network port of WTP */
|
||||
if (config_lookup_int(config, "application.network.port", &configLongInt) == CONFIG_TRUE) {
|
||||
if ((configLongInt > 0) && (configLongInt < 65536)) {
|
||||
g_wtp.net.bind_sock_ctrl_port = (unsigned short)configLongInt;
|
||||
} else {
|
||||
capwap_logging_error("Invalid configuration file, invalid application.network.port 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 ipv4 & ipv6 of WTP */
|
||||
if (config_lookup_bool(config, "application.network.ipv4", &configIPv4) != CONFIG_TRUE) {
|
||||
configIPv4 = 1;
|
||||
}
|
||||
|
||||
if (config_lookup_bool(config, "application.network.ipv6", &configIPv6) != CONFIG_TRUE) {
|
||||
configIPv6 = 1;
|
||||
}
|
||||
|
||||
if (configIPv4 && configIPv6) {
|
||||
g_wtp.net.sock_family = AF_UNSPEC;
|
||||
} else if (!configIPv4 && !configIPv6) {
|
||||
capwap_logging_error("Invalid configuration file, request enable application.network.ipv4 or application.network.ipv6");
|
||||
return 0;
|
||||
} else {
|
||||
g_wtp.net.sock_family = (configIPv4 ? AF_INET : AF_INET6);
|
||||
}
|
||||
|
||||
/* Set ip dual stack of WTP */
|
||||
if (config_lookup_bool(config, "application.network.ipdualstack", &configInt) == CONFIG_TRUE) {
|
||||
if (!configInt) {
|
||||
g_wtp.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG;
|
||||
g_wtp.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG;
|
||||
} else {
|
||||
g_wtp.net.bind_ctrl_flags &= ~CAPWAP_IPV6ONLY_FLAG;
|
||||
g_wtp.net.bind_data_flags &= ~CAPWAP_IPV6ONLY_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set search discovery of WTP */
|
||||
if (config_lookup_bool(config, "application.acdiscovery.search", &configInt) == CONFIG_TRUE) {
|
||||
g_wtp.acdiscoveryrequest = (configInt ? 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 sockaddr_storage acaddr;
|
||||
|
||||
/* Parsing address */
|
||||
if (capwap_address_from_string(address, &acaddr)) {
|
||||
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
|
||||
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
|
||||
}
|
||||
|
||||
wtp_add_acaddress(&acaddr, g_wtp.acdiscoveryarray);
|
||||
g_wtp.discoverytype.type = CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_STATIC;
|
||||
} 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);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
const char* address = config_setting_get_string_elem(configSetting, i);
|
||||
if (address != NULL) {
|
||||
struct sockaddr_storage acaddr;
|
||||
|
||||
/* Parsing address */
|
||||
if (capwap_address_from_string(address, &acaddr)) {
|
||||
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
|
||||
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
|
||||
}
|
||||
|
||||
wtp_add_acaddress(&acaddr, g_wtp.acpreferedarray);
|
||||
} 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) {
|
||||
/* If request add default acdiscovery */
|
||||
if (!g_wtp.acdiscoveryarray->count) {
|
||||
if (!wtp_add_default_acaddress()) {
|
||||
capwap_logging_debug("Unable add default AC discovery");
|
||||
return WTP_ERROR_NETWORK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bind to any address */
|
||||
if (!capwap_bind_sockets(&g_wtp.net)) {
|
||||
capwap_logging_fatal("Cannot bind address");
|
||||
return WTP_ERROR_NETWORK;
|
||||
}
|
||||
|
||||
return CAPWAP_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/* */
|
||||
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");
|
||||
return CAPWAP_REQUEST_ROOT;
|
||||
}
|
||||
|
||||
/* Init random generator */
|
||||
capwap_init_rand();
|
||||
|
||||
/* Init crypt */
|
||||
if (!capwap_crypt_init()) {
|
||||
capwap_logging_fatal("Error to init crypt engine");
|
||||
return CAPWAP_CRYPT_ERROR;
|
||||
}
|
||||
|
||||
/* Alloc a WTP */
|
||||
if (!wtp_init()) {
|
||||
capwap_logging_fatal("Error to init WTP engine");
|
||||
return WTP_ERROR_SYSTEM_FAILER;
|
||||
}
|
||||
|
||||
/* Read configuration file */
|
||||
value = wtp_load_configuration(argc, argv);
|
||||
if (value < 0) {
|
||||
result = WTP_ERROR_LOAD_CONFIGURATION;
|
||||
} else if (value > 0) {
|
||||
capwap_logging_info("Startup WTP");
|
||||
|
||||
/* Start WTP */
|
||||
wtp_dfa_change_state(CAPWAP_START_TO_IDLE_STATE);
|
||||
|
||||
/* Complete configuration WTP */
|
||||
result = wtp_configure();
|
||||
if (result == CAPWAP_SUCCESSFUL) {
|
||||
/* Init complete */
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_STATE);
|
||||
|
||||
/* Running WTP */
|
||||
result = wtp_dfa_execute();
|
||||
|
||||
/* Close socket */
|
||||
capwap_close_sockets(&g_wtp.net);
|
||||
}
|
||||
|
||||
capwap_logging_info("Terminate WTP");
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
wtp_destroy();
|
||||
|
||||
/* Free crypt */
|
||||
capwap_crypt_free();
|
||||
|
||||
/* Check memory leak */
|
||||
if (capwap_check_memory_leak(1)) {
|
||||
if (result == CAPWAP_SUCCESSFUL)
|
||||
result = WTP_ERROR_MEMORY_LEAK;
|
||||
}
|
||||
|
||||
/* Close logging */
|
||||
capwap_logging_close();
|
||||
|
||||
return result;
|
||||
}
|
147
src/wtp/wtp.h
Normal file
147
src/wtp/wtp.h
Normal file
@ -0,0 +1,147 @@
|
||||
#ifndef __CAPWAP_WTP_HEADER__
|
||||
#define __CAPWAP_WTP_HEADER__
|
||||
|
||||
/* standard include */
|
||||
#include "capwap.h"
|
||||
#include "capwap_dtls.h"
|
||||
#include "capwap_network.h"
|
||||
#include "capwap_protocol.h"
|
||||
|
||||
/* WTP Configuration */
|
||||
#define WTP_STANDARD_CONFIGURATION_FILE "/etc/capwap/wtp.conf"
|
||||
|
||||
/* WTP runtime error return code */
|
||||
#define WTP_ERROR_SYSTEM_FAILER -1000
|
||||
#define WTP_ERROR_LOAD_CONFIGURATION -1001
|
||||
#define WTP_ERROR_NETWORK -1002
|
||||
#define WTP_ERROR_MEMORY_LEAK 1
|
||||
|
||||
/* Min and max dfa values */
|
||||
#define WTP_MIN_DISCOVERY_INTERVAL 2
|
||||
#define WTP_DEFAULT_DISCOVERY_INTERVAL 20
|
||||
#define WTP_MAX_DISCOVERY_INTERVAL 180
|
||||
#define WTP_DEFAULT_DISCOVERY_COUNT 10
|
||||
#define WTP_DEFAULT_SILENT_INTERVAL 30
|
||||
#define WTP_DEFAULT_RETRANSMIT_INTERVAL 3
|
||||
#define WTP_MAX_RETRANSMIT 5
|
||||
#define WTP_MIN_WAITDTLS_INTERVAL 30
|
||||
#define WTP_DEFAULT_WAITDTLS_INTERVAL 60
|
||||
#define WTP_DEFAULT_STATISTICSTIMER_INTERVAL 120
|
||||
#define WTP_DEFAULT_DATACHANNEL_KEEPALIVE 30
|
||||
#define WTP_DEFAULT_DATACHANNEL_KEEPALIVEDEAD 60
|
||||
#define WTP_MAX_DATACHANNEL_KEEPALIVEDEAD 240
|
||||
#define WTP_DEFAULT_ECHO_INTERVAL 30
|
||||
#define WTP_DEFAULT_DTLS_SESSION_DELETE 5
|
||||
#define WTP_DEFAULT_FAILED_DTLS_SESSION_RETRY 3
|
||||
|
||||
/* WTP State machine */
|
||||
struct wtp_state {
|
||||
unsigned long state;
|
||||
|
||||
/* Discovery Information */
|
||||
int rfcDiscoveryInterval;
|
||||
int rfcMaxDiscoveryInterval;
|
||||
int rfcDiscoveryCount;
|
||||
int rfcMaxDiscoveries;
|
||||
|
||||
/* Sulking Information */
|
||||
int rfcSilentInterval;
|
||||
|
||||
/* Run */
|
||||
int rfcEchoInterval;
|
||||
|
||||
/* Dtls Information */
|
||||
int rfcFailedDTLSSessionCount;
|
||||
int rfcFailedDTLSAuthFailCount;
|
||||
int rfcMaxFailedDTLSSessionRetry;
|
||||
|
||||
/* Request retransmit */
|
||||
int rfcRetransmitInterval;
|
||||
int rfcRetransmitCount;
|
||||
int rfcMaxRetransmit;
|
||||
|
||||
/* Data channel */
|
||||
int rfcDataChannelKeepAlive;
|
||||
int rfcDataChannelDeadInterval;
|
||||
|
||||
/* Dtls */
|
||||
int rfcWaitDTLS;
|
||||
int rfcDTLSSessionDelete;
|
||||
};
|
||||
|
||||
/* WTP */
|
||||
struct wtp_t {
|
||||
int running;
|
||||
|
||||
struct wtp_state dfa;
|
||||
struct capwap_network net;
|
||||
|
||||
struct capwap_wtpname_element name;
|
||||
struct capwap_acname_element acname;
|
||||
struct capwap_location_element location;
|
||||
|
||||
unsigned short binding;
|
||||
|
||||
struct capwap_discoverytype_element discoverytype;
|
||||
struct capwap_wtpframetunnelmode_element mactunnel;
|
||||
struct capwap_wtpmactype_element mactype;
|
||||
struct capwap_wtpboarddata_element boarddata;
|
||||
struct capwap_wtpdescriptor_element descriptor;
|
||||
|
||||
struct capwap_sessionid_element sessionid;
|
||||
|
||||
struct capwap_ecnsupport_element ecn;
|
||||
struct capwap_transport_element transport;
|
||||
struct capwap_statisticstimer_element statisticstimer;
|
||||
struct capwap_wtprebootstat_element rebootstat;
|
||||
|
||||
unsigned char localseqnumber;
|
||||
unsigned char remoteseqnumber;
|
||||
unsigned short mtu;
|
||||
unsigned short fragmentid;
|
||||
capwap_fragment_packet_array* requestfragmentpacket;
|
||||
capwap_fragment_packet_array* responsefragmentpacket;
|
||||
unsigned char lastrecvpackethash[16];
|
||||
|
||||
/* */
|
||||
int acdiscoveryrequest;
|
||||
unsigned long acpreferedselected;
|
||||
struct capwap_array* acdiscoveryarray;
|
||||
struct capwap_array* acpreferedarray;
|
||||
struct capwap_array* acdiscoveryresponse;
|
||||
|
||||
struct sockaddr_storage wtpctrladdress;
|
||||
struct sockaddr_storage wtpdataaddress;
|
||||
struct sockaddr_storage acctrladdress;
|
||||
struct sockaddr_storage acdataaddress;
|
||||
struct capwap_socket acctrlsock;
|
||||
struct capwap_socket acdatasock;
|
||||
|
||||
struct capwap_array* radios;
|
||||
|
||||
/* Dtls */
|
||||
int enabledtls;
|
||||
unsigned char dtlsdatapolicy;
|
||||
unsigned char validdtlsdatapolicy;
|
||||
struct capwap_dtls_context dtlscontext;
|
||||
struct capwap_dtls ctrldtls;
|
||||
struct capwap_dtls datadtls;
|
||||
};
|
||||
|
||||
#define WTP_RADIO_ENABLED 0
|
||||
#define WTP_RADIO_DISABLED 1
|
||||
#define WTP_RADIO_HWFAILURE 2
|
||||
#define WTP_RADIO_SWFAILURE 3
|
||||
|
||||
struct wtp_radio {
|
||||
char device[IFNAMSIZ];
|
||||
struct capwap_80211_wtpradioinformation_element radioinformation;
|
||||
int status;
|
||||
};
|
||||
|
||||
extern struct wtp_t g_wtp;
|
||||
|
||||
/* */
|
||||
int wtp_update_radio_in_use();
|
||||
|
||||
#endif /* __CAPWAP_WTP_HEADER__ */
|
459
src/wtp/wtp_dfa.c
Normal file
459
src/wtp/wtp_dfa.c
Normal file
@ -0,0 +1,459 @@
|
||||
#include "wtp.h"
|
||||
#include "wtp_dfa.h"
|
||||
#include "capwap_array.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_dtls.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/* Handler signal */
|
||||
static void wtp_signal_handler(int signum) {
|
||||
if ((signum == SIGINT) || (signum == SIGTERM)) {
|
||||
g_wtp.running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* WTP state machine */
|
||||
int wtp_dfa_execute(void) {
|
||||
int result = CAPWAP_SUCCESSFUL;
|
||||
int action = WTP_DFA_NO_PACKET;
|
||||
struct timeout_control timeout;
|
||||
|
||||
struct capwap_packet packet;
|
||||
capwap_fragment_list* defraglist;
|
||||
char buffer[CAPWAP_MAX_PACKET_SIZE];
|
||||
int buffersize;
|
||||
|
||||
int index;
|
||||
struct sockaddr_storage recvfromaddr;
|
||||
struct sockaddr_storage recvtoaddr;
|
||||
int isrecvpacket = 0;
|
||||
|
||||
struct pollfd* fds;
|
||||
int fdscount;
|
||||
|
||||
/* Init */
|
||||
capwap_init_timeout(&timeout);
|
||||
capwap_set_timeout(0, &timeout, CAPWAP_TIMER_CONTROL_CONNECTION); /* Start DFA with timeout */
|
||||
|
||||
memset(&packet, 0, sizeof(struct capwap_packet));
|
||||
defraglist = capwap_defragment_init_list();
|
||||
|
||||
/* Configure poll struct */
|
||||
fdscount = CAPWAP_MAX_SOCKETS * 2;
|
||||
fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fdscount);
|
||||
if (!fds) {
|
||||
capwap_outofmemory();
|
||||
}
|
||||
|
||||
/* Retrive all socket for polling */
|
||||
fdscount = capwap_network_set_pollfd(&g_wtp.net, fds, fdscount);
|
||||
ASSERT(fdscount > 0);
|
||||
|
||||
/* Handler signal */
|
||||
g_wtp.running = 1;
|
||||
signal(SIGINT, wtp_signal_handler);
|
||||
signal(SIGTERM, wtp_signal_handler);
|
||||
|
||||
for (;;) {
|
||||
/* If request wait packet from AC */
|
||||
isrecvpacket = 0;
|
||||
if ((action == WTP_DFA_ACCEPT_PACKET) || (action == WTP_DFA_DROP_PACKET)) {
|
||||
buffersize = CAPWAP_MAX_PACKET_SIZE;
|
||||
index = capwap_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, &timeout);
|
||||
if (!g_wtp.running) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
if (action == WTP_DFA_DROP_PACKET) {
|
||||
/* Drop packet */
|
||||
continue;
|
||||
} else {
|
||||
int check;
|
||||
|
||||
/* Check of packet */
|
||||
capwap_get_network_socket(&g_wtp.net, &packet.socket, fds[index].fd);
|
||||
check = capwap_sanity_check(packet.socket.isctrlsocket, g_wtp.dfa.state, buffer, buffersize, g_wtp.ctrldtls.enable, g_wtp.datadtls.enable);
|
||||
if (check == CAPWAP_DTLS_PACKET) {
|
||||
struct capwap_dtls* dtls = (packet.socket.isctrlsocket ? &g_wtp.ctrldtls : &g_wtp.datadtls);
|
||||
|
||||
if (dtls->enable) {
|
||||
int oldaction = dtls->action;
|
||||
|
||||
/* Decrypt packet */
|
||||
buffersize = capwap_decrypt_packet(dtls, buffer, buffersize, NULL, CAPWAP_MAX_PACKET_SIZE);
|
||||
if (buffersize > 0) {
|
||||
check = CAPWAP_PLAIN_PACKET;
|
||||
} else if (buffersize == CAPWAP_ERROR_AGAIN) {
|
||||
/* Check is handshake complete */
|
||||
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) {
|
||||
if (packet.socket.isctrlsocket) {
|
||||
if (g_wtp.dfa.state == CAPWAP_DTLS_CONNECT_STATE) {
|
||||
check = CAPWAP_NONE_PACKET;
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_TO_JOIN_STATE);
|
||||
action = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* TODO */ /* Connection error */
|
||||
check = CAPWAP_WRONG_PACKET;
|
||||
}
|
||||
} else {
|
||||
if (g_wtp.dfa.state == CAPWAP_DATA_CHECK_TO_RUN_STATE) {
|
||||
check = CAPWAP_NONE_PACKET;
|
||||
action = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* TODO */ /* Connection error */
|
||||
check = CAPWAP_WRONG_PACKET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue; /* Next packet */
|
||||
} else {
|
||||
if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
|
||||
action = wtp_teardown_connection(&timeout);
|
||||
}
|
||||
|
||||
continue; /* Next packet */
|
||||
}
|
||||
} else {
|
||||
continue; /* Drop packet */
|
||||
}
|
||||
} else if (check == CAPWAP_WRONG_PACKET) {
|
||||
capwap_logging_debug("Warning: sanity check failure");
|
||||
/* Drop packet */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* */
|
||||
if (check == CAPWAP_PLAIN_PACKET) {
|
||||
/* If request, defragmentation packet */
|
||||
check = capwap_defragment_packets(&recvfromaddr, buffer, buffersize, defraglist, &packet);
|
||||
if (check == CAPWAP_REQUEST_MORE_FRAGMENT) {
|
||||
continue;
|
||||
} else if (check != CAPWAP_RECEIVE_COMPLETE_PACKET) {
|
||||
/* Discard fragments */
|
||||
capwap_defragment_remove_sender(defraglist, &recvfromaddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Detect local address */
|
||||
if (recvtoaddr.ss_family == AF_UNSPEC) {
|
||||
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
|
||||
struct sockaddr_storage sockinfo;
|
||||
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
|
||||
|
||||
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
|
||||
if (getsockname(fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo));
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive a complete packet */
|
||||
isrecvpacket = 1;
|
||||
memcpy(&packet.localaddr, &recvtoaddr, sizeof(struct sockaddr_storage));
|
||||
memcpy(&packet.remoteaddr, &recvfromaddr, sizeof(struct sockaddr_storage));
|
||||
|
||||
/* Check for already response to packet */
|
||||
if (packet.socket.isctrlsocket) {
|
||||
if (capwap_recv_retrasmitted_request(&g_wtp.ctrldtls, &packet, g_wtp.remoteseqnumber, g_wtp.lastrecvpackethash, &g_wtp.acctrlsock, g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_free_packet(&packet);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check message type */
|
||||
if (!capwap_check_message_type(&g_wtp.ctrldtls, &packet, g_wtp.mtu)) {
|
||||
capwap_free_packet(&packet);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (index == CAPWAP_RECV_ERROR_INTR) {
|
||||
/* Ignore recv */
|
||||
continue;
|
||||
} else if (index == CAPWAP_RECV_ERROR_SOCKET) {
|
||||
/* Socket close */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute state */
|
||||
switch (g_wtp.dfa.state) {
|
||||
case CAPWAP_IDLE_STATE: {
|
||||
action = wtp_dfa_state_idle((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_IDLE_TO_DISCOVERY_STATE: {
|
||||
action = wtp_dfa_state_idle_to_discovery((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_IDLE_TO_DTLS_SETUP_STATE: {
|
||||
action = wtp_dfa_state_idle_to_dtlssetup((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DISCOVERY_STATE: {
|
||||
action = wtp_dfa_state_discovery((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DISCOVERY_TO_SULKING_STATE: {
|
||||
action = wtp_dfa_state_discovery_to_sulking((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DISCOVERY_TO_DTLS_SETUP_STATE: {
|
||||
action = wtp_dfa_state_discovery_to_dtlssetup((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_SULKING_STATE: {
|
||||
action = wtp_dfa_state_sulking((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_SULKING_TO_IDLE_STATE: {
|
||||
action = wtp_dfa_state_sulking_to_idle((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_SETUP_STATE: {
|
||||
action = wtp_dfa_state_dtlssetup((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_SETUP_TO_IDLE_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_SETUP_TO_SULKING_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_SETUP_TO_AUTHORIZE_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_AUTHORIZE_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_AUTHORIZE_TO_DTLS_SETUP_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_AUTHORIZE_TO_DTLS_CONNECT_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_AUTHORIZE_TO_DTLS_TEARDOWN_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_CONNECT_STATE: {
|
||||
action = wtp_dfa_state_dtlsconnect((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_dtlsconnect_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_CONNECT_TO_JOIN_STATE: {
|
||||
action = wtp_dfa_state_dtlsconnect_to_join((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_TEARDOWN_TO_IDLE_STATE: {
|
||||
action = wtp_dfa_state_dtlsteardown_to_idle((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DTLS_TEARDOWN_TO_SULKING_STATE: {
|
||||
action = wtp_dfa_state_dtlsteardown_to_sulking((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_JOIN_STATE: {
|
||||
action = wtp_dfa_state_join((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_join_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_JOIN_TO_IMAGE_DATA_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_JOIN_TO_CONFIGURE_STATE: {
|
||||
action = wtp_dfa_state_join_to_configure((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_IMAGE_DATA_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_IMAGE_DATA_TO_RESET_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_IMAGE_DATA_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_imagedata_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CONFIGURE_STATE: {
|
||||
action = wtp_dfa_state_configure((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CONFIGURE_TO_RESET_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_configure_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CONFIGURE_TO_DATA_CHECK_STATE: {
|
||||
action = wtp_dfa_state_configure_to_datacheck((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RESET_STATE: {
|
||||
action = wtp_dfa_state_reset((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DATA_CHECK_STATE: {
|
||||
action = wtp_dfa_state_datacheck((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_datacheck_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DATA_CHECK_TO_RUN_STATE: {
|
||||
action = wtp_dfa_state_datacheck_to_run((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RUN_STATE: {
|
||||
action = wtp_dfa_state_run((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE: {
|
||||
action = wtp_dfa_state_run_to_dtlsteardown((isrecvpacket ? &packet : NULL), &timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RUN_TO_RESET_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DEAD_STATE: {
|
||||
/* Never called with this state */
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
capwap_logging_debug("Unknown action event: %lu", g_wtp.dfa.state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
if (isrecvpacket) {
|
||||
capwap_free_packet(&packet);
|
||||
} else {
|
||||
capwap_defragment_flush_list(defraglist);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DTSL Control */
|
||||
if (g_wtp.ctrldtls.enable) {
|
||||
capwap_crypt_close(&g_wtp.ctrldtls);
|
||||
capwap_crypt_freesession(&g_wtp.ctrldtls);
|
||||
}
|
||||
|
||||
/* Free DTLS Data */
|
||||
if (g_wtp.datadtls.enable) {
|
||||
capwap_crypt_close(&g_wtp.datadtls);
|
||||
capwap_crypt_freesession(&g_wtp.datadtls);
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
capwap_defragment_free_list(defraglist);
|
||||
capwap_free(fds);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Change WTP state machine */
|
||||
void wtp_dfa_change_state(int state) {
|
||||
if (state != g_wtp.dfa.state) {
|
||||
capwap_logging_debug("WTP change state from %s to %s", capwap_dfa_getname(g_wtp.dfa.state), capwap_dfa_getname(state));
|
||||
g_wtp.dfa.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
void wtp_free_reference_last_request(void) {
|
||||
capwap_fragment_free(g_wtp.requestfragmentpacket);
|
||||
}
|
||||
|
||||
/* */
|
||||
void wtp_free_reference_last_response(void) {
|
||||
capwap_fragment_free(g_wtp.responsefragmentpacket);
|
||||
memset(&g_wtp.lastrecvpackethash[0], 0, sizeof(g_wtp.lastrecvpackethash));
|
||||
}
|
76
src/wtp/wtp_dfa.h
Normal file
76
src/wtp/wtp_dfa.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef __WTP_DFA_HEADER__
|
||||
#define __WTP_DFA_HEADER__
|
||||
|
||||
#include "wtp.h"
|
||||
#include "capwap_network.h"
|
||||
#include "capwap_protocol.h"
|
||||
#include "capwap_element.h"
|
||||
|
||||
/* Execute WTP DFA */
|
||||
#define WTP_DFA_NO_PACKET 1
|
||||
#define WTP_DFA_ACCEPT_PACKET 2
|
||||
#define WTP_DFA_DROP_PACKET 3
|
||||
|
||||
/* */
|
||||
struct wtp_discovery_response {
|
||||
struct sockaddr_storage acaddr;
|
||||
struct capwap_build_packet* packet;
|
||||
struct capwap_element_discovery_response discoveryresponse;
|
||||
};
|
||||
|
||||
void wtp_free_discovery_response_array(void);
|
||||
|
||||
/* */
|
||||
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param);
|
||||
|
||||
/* */
|
||||
int wtp_teardown_connection(struct timeout_control* timeout);
|
||||
|
||||
/* */
|
||||
void wtp_free_reference_last_request(void);
|
||||
void wtp_free_reference_last_response(void);
|
||||
|
||||
/* State machine */
|
||||
int wtp_dfa_execute(void);
|
||||
void wtp_dfa_change_state(int state);
|
||||
|
||||
int wtp_dfa_state_idle(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_idle_to_discovery(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_idle_to_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_discovery_to_sulking(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_discovery_to_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_sulking(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_sulking_to_idle(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_dtlsconnect(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_dtlsconnect_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_dtlsteardown_to_sulking(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_dtlsteardown_to_idle(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_dtlsconnect_to_join(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_join(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_join_to_configure(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_join_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_imagedata_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_configure(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_configure_to_datacheck(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_configure_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_datacheck(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_datacheck_to_run(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_datacheck_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_run(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
int wtp_dfa_state_run_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
int wtp_dfa_state_reset(struct capwap_packet* packet, struct timeout_control* timeout);
|
||||
|
||||
#endif /* __WTP_DFA_HEADER__ */
|
181
src/wtp/wtp_dfa_configure.c
Normal file
181
src/wtp/wtp_dfa_configure.c
Normal file
@ -0,0 +1,181 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_element.h"
|
||||
#include "capwap_array.h"
|
||||
#include "capwap_list.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
static unsigned long wtp_configure_ac(struct capwap_element_configurationstatus_response* configureresponse) {
|
||||
/* TODO: gestione richiesta */
|
||||
|
||||
/* */
|
||||
g_wtp.dfa.rfcMaxDiscoveryInterval = configureresponse->timers->discovery;
|
||||
g_wtp.dfa.rfcEchoInterval = configureresponse->timers->echorequest;
|
||||
|
||||
return CAPWAP_CONFIGURE_TO_DATA_CHECK_STATE;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_configure(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
if (packet) {
|
||||
if (!capwap_compare_ip(&g_wtp.acctrladdress, &packet->remoteaddr)) {
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
/* Parsing packet */
|
||||
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||||
if (buildpacket) {
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
unsigned short binding;
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
if ((binding == g_wtp.binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_CONFIGURATION_STATUS_RESPONSE) && ((g_wtp.localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
|
||||
struct capwap_element_configurationstatus_response configureresponse;
|
||||
|
||||
/* Valid packet, free request packet */
|
||||
wtp_free_reference_last_request();
|
||||
|
||||
/* Configuration status response info */
|
||||
capwap_init_element_configurationstatus_response(&configureresponse, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_configurationstatus_response(&configureresponse, buildpacket->elementslist->first)) {
|
||||
wtp_dfa_change_state(wtp_configure_ac(&configureresponse));
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* Free join response */
|
||||
capwap_free_element_configurationstatus_response(&configureresponse, binding);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
capwap_build_packet_free(buildpacket);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* No Configuration status response received */
|
||||
g_wtp.dfa.rfcRetransmitCount++;
|
||||
if (g_wtp.dfa.rfcRetransmitCount >= g_wtp.dfa.rfcMaxRetransmit) {
|
||||
/* Timeout join state */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Retransmit configuration request */
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send configuration status request packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update timeout */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int wtp_dfa_state_configure_to_datacheck(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
unsigned long i;
|
||||
int result = -1;
|
||||
int status = WTP_DFA_NO_PACKET;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
struct capwap_resultcode_element resultcode;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding);
|
||||
buildpacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare change state event request */
|
||||
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_CHANGE_STATE_EVENT_REQUEST, g_wtp.localseqnumber++);
|
||||
|
||||
for (i = 0; i < g_wtp.radios->count; i++) {
|
||||
struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i);
|
||||
struct capwap_radiooprstate_element radiooprstate;
|
||||
|
||||
radiooprstate.radioid = (unsigned char)(i + 1);
|
||||
radiooprstate.state = ((radio->status == WTP_RADIO_ENABLED) ? CAPWAP_RADIO_OPERATIONAL_STATE_ENABLED : CAPWAP_RADIO_OPERATIONAL_STATE_DISABLED);
|
||||
|
||||
if (radiooprstate.state == WTP_RADIO_ENABLED) {
|
||||
radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_NORMAL;
|
||||
} else if (radiooprstate.state == WTP_RADIO_DISABLED) {
|
||||
radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_ADMINSET;
|
||||
} else if (radiooprstate.state == WTP_RADIO_HWFAILURE) {
|
||||
radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_RADIOFAILURE;
|
||||
} else if (radiooprstate.state == WTP_RADIO_SWFAILURE) {
|
||||
radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_SOFTWAREFAILURE;
|
||||
}
|
||||
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_RADIOOPRSTATE_ELEMENT(&radiooprstate));
|
||||
}
|
||||
|
||||
resultcode.code = CAPWAP_RESULTCODE_SUCCESS;
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_RESULTCODE_ELEMENT(&resultcode));
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
/* Create change state event request packet */
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
wtp_free_reference_last_request();
|
||||
result = capwap_fragment_build_packet(buildpacket, g_wtp.requestfragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Warning: build invalid change state event request packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send change state event request to AC */
|
||||
if (result >= 0) {
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send change state event request packet");
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
/* Error to send packets */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
|
||||
} else {
|
||||
g_wtp.dfa.rfcRetransmitCount = 0;
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE);
|
||||
status = WTP_DFA_ACCEPT_PACKET;
|
||||
}
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_configure_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
165
src/wtp/wtp_dfa_datacheck.c
Normal file
165
src/wtp/wtp_dfa_datacheck.c
Normal file
@ -0,0 +1,165 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_element.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
static unsigned long wtp_datacheck_ac(struct capwap_element_changestateevent_response* changestateresponse) {
|
||||
/* TODO: gestione richiesta */
|
||||
|
||||
return CAPWAP_DATA_CHECK_TO_RUN_STATE;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_datacheck(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
if (packet) {
|
||||
if (!capwap_compare_ip(&g_wtp.acctrladdress, &packet->remoteaddr)) {
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
/* Parsing packet */
|
||||
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||||
if (buildpacket) {
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
unsigned short binding;
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
if ((binding == g_wtp.binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_CHANGE_STATE_EVENT_RESPONSE) && ((g_wtp.localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
|
||||
struct capwap_element_changestateevent_response changestateresponse;
|
||||
|
||||
/* Valid packet, free request packet */
|
||||
wtp_free_reference_last_request();
|
||||
|
||||
/* Configuration status response info */
|
||||
capwap_init_element_changestateevent_response(&changestateresponse, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_changestateevent_response(&changestateresponse, buildpacket->elementslist->first)) {
|
||||
wtp_dfa_change_state(wtp_datacheck_ac(&changestateresponse));
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* Free join response */
|
||||
capwap_free_element_changestateevent_response(&changestateresponse, binding);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
capwap_build_packet_free(buildpacket);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* No change state response received */
|
||||
g_wtp.dfa.rfcRetransmitCount++;
|
||||
if (g_wtp.dfa.rfcRetransmitCount >= g_wtp.dfa.rfcMaxRetransmit) {
|
||||
/* Timeout join state */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Retransmit change state request */
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send change state request packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update timeout */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_datacheck_to_run(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int result;
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
capwap_fragment_packet_array* txfragpacket;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* If need, create DTLS Data channel crypted */
|
||||
if (g_wtp.dtlsdatapolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) {
|
||||
if (!g_wtp.datadtls.enable) {
|
||||
/* Create DTLS data session before send data keepalive */
|
||||
if (capwap_crypt_createsession(&g_wtp.datadtls, CAPWAP_DTLS_DATA_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) {
|
||||
if (capwap_crypt_open(&g_wtp.datadtls, &g_wtp.acdataaddress) == CAPWAP_HANDSHAKE_CONTINUE) {
|
||||
/* Wait complete dtls handshake */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcWaitDTLS, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
return WTP_DFA_ACCEPT_PACKET;
|
||||
} else {
|
||||
/* TODO error */
|
||||
}
|
||||
} else {
|
||||
/* TODO error */
|
||||
}
|
||||
} else if (g_wtp.datadtls.action != CAPWAP_DTLS_ACTION_DATA) {
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, CAPWAP_WIRELESS_BINDING_NONE);
|
||||
buildpacket->isctrlmsg = 0;
|
||||
|
||||
/* */
|
||||
SET_FLAG_K_HEADER(&buildpacket->header, 1);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_SESSIONID_ELEMENT(&g_wtp.sessionid));
|
||||
|
||||
txfragpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
|
||||
result = capwap_fragment_build_packet(buildpacket, txfragpacket, CAPWAP_DONT_FRAGMENT, 0);
|
||||
if (!result) {
|
||||
struct capwap_packet* txpacket;
|
||||
|
||||
ASSERT(txfragpacket->count == 1);
|
||||
|
||||
txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(txfragpacket, 0);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
|
||||
capwap_logging_debug("Warning: error to send data channel keepalive packet");
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
capwap_fragment_free(txfragpacket);
|
||||
capwap_array_free(txfragpacket);
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send Configuration Status request to AC */
|
||||
if (!result) {
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcEchoInterval, timeout, CAPWAP_TIMER_CONTROL_ECHO);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDataChannelDeadInterval, timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD);
|
||||
wtp_dfa_change_state(CAPWAP_RUN_STATE);
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_datacheck_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
298
src/wtp/wtp_dfa_discovery.c
Normal file
298
src/wtp/wtp_dfa_discovery.c
Normal file
@ -0,0 +1,298 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_element.h"
|
||||
#include "capwap_array.h"
|
||||
#include "capwap_list.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
void wtp_free_discovery_response_array(void) {
|
||||
int i;
|
||||
|
||||
/* Free items */
|
||||
for (i = 0; i < g_wtp.acdiscoveryresponse->count; i++) {
|
||||
struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, i);
|
||||
|
||||
capwap_free_element_discovery_response(&response->discoveryresponse, GET_WBID_HEADER(&response->packet->header));
|
||||
capwap_build_packet_free(response->packet);
|
||||
}
|
||||
|
||||
/* Remove all items */
|
||||
capwap_array_resize(g_wtp.acdiscoveryresponse, 0);
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_discovery(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
if (packet) {
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||||
if (buildpacket) {
|
||||
if (capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
capwap_build_packet_free(buildpacket); /* Invalid packet */
|
||||
} else {
|
||||
unsigned short binding;
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
if ((binding != g_wtp.binding) || (ntohl(buildpacket->ctrlmsg.type) != CAPWAP_DISCOVERY_RESPONSE) || ((g_wtp.localseqnumber - 1) != buildpacket->ctrlmsg.seq)) {
|
||||
capwap_build_packet_free(buildpacket); /* Invalid packet */
|
||||
} else {
|
||||
struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, g_wtp.acdiscoveryresponse->count);
|
||||
|
||||
/* Discovery response info */
|
||||
memcpy(&response->acaddr, &packet->remoteaddr, sizeof(struct sockaddr_storage));
|
||||
response->packet = buildpacket;
|
||||
capwap_init_element_discovery_response(&response->discoveryresponse, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
capwap_parsing_element_discovery_response(&response->discoveryresponse, buildpacket->elementslist->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (g_wtp.acdiscoveryresponse->count > 0) {
|
||||
int i, j, w;
|
||||
int countwtp = -1;
|
||||
int indexpreferred = -1;
|
||||
|
||||
struct sockaddr_storage checkaddr;
|
||||
struct sockaddr_in* checkaddripv4;
|
||||
struct sockaddr_in6* checkaddripv6;
|
||||
|
||||
/* */
|
||||
g_wtp.acctrladdress.ss_family = AF_UNSPEC;
|
||||
|
||||
/* Selected by preferred or less WTP by AC */
|
||||
for (i = 0; i < g_wtp.acdiscoveryresponse->count; i++) {
|
||||
struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, i);
|
||||
|
||||
/* AC with IPv4 */
|
||||
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET)) {
|
||||
for (w = 0; w < response->discoveryresponse.controlipv4->count; w++) {
|
||||
struct capwap_controlipv4_element* controlipv4 = *(struct capwap_controlipv4_element**)capwap_array_get_item_pointer(response->discoveryresponse.controlipv4, w);
|
||||
|
||||
/* Create IPv4 address */
|
||||
checkaddripv4 = (struct sockaddr_in*)&checkaddr;
|
||||
checkaddripv4->sin_family = AF_INET;
|
||||
checkaddripv4->sin_port = htons(CAPWAP_CONTROL_PORT);
|
||||
memcpy(&checkaddripv4->sin_addr, &controlipv4->address, sizeof(struct in_addr));
|
||||
|
||||
/* Check for preferred AC */
|
||||
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
|
||||
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
|
||||
|
||||
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
|
||||
indexpreferred = j;
|
||||
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check by number of WTP */
|
||||
if (indexpreferred == -1) {
|
||||
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
|
||||
countwtp = controlipv4->wtpcount;
|
||||
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* AC with IPv6 */
|
||||
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET6)) {
|
||||
for (w = 0; w < response->discoveryresponse.controlipv6->count; w++) {
|
||||
struct capwap_controlipv6_element* controlipv6 = *(struct capwap_controlipv6_element**)capwap_array_get_item_pointer(response->discoveryresponse.controlipv6, w);
|
||||
|
||||
/* Create IPv6 address */
|
||||
checkaddripv6 = (struct sockaddr_in6*)&checkaddr;
|
||||
checkaddripv6->sin6_family = AF_INET6;
|
||||
checkaddripv6->sin6_port = htons(CAPWAP_CONTROL_PORT);
|
||||
memcpy(&checkaddripv6->sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
|
||||
|
||||
/* Check for preferred AC */
|
||||
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
|
||||
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
|
||||
|
||||
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
|
||||
indexpreferred = j;
|
||||
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check by number of WTP */
|
||||
if (indexpreferred == -1) {
|
||||
if ((countwtp == -1) || (countwtp > controlipv6->wtpcount)) {
|
||||
countwtp = controlipv6->wtpcount;
|
||||
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
wtp_free_discovery_response_array();
|
||||
|
||||
/* Change state if found AC */
|
||||
if (g_wtp.acctrladdress.ss_family != AF_UNSPEC) {
|
||||
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage));
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
|
||||
wtp_dfa_change_state(CAPWAP_DISCOVERY_TO_DTLS_SETUP_STATE);
|
||||
}
|
||||
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
int i;
|
||||
int result;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
/* No Discovery response received */
|
||||
g_wtp.dfa.rfcDiscoveryCount++;
|
||||
if (g_wtp.dfa.rfcDiscoveryCount >= g_wtp.dfa.rfcMaxDiscoveries) {
|
||||
/* Timeout discovery state */
|
||||
wtp_dfa_change_state(CAPWAP_DISCOVERY_TO_SULKING_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Update status radio */
|
||||
g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use();
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding);
|
||||
buildpacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare discovery request */
|
||||
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_DISCOVERY_REQUEST, g_wtp.localseqnumber++);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_DISCOVERYTYPE_ELEMENT(&g_wtp.discoverytype));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPBOARDDATA_ELEMENT(&g_wtp.boarddata));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPDESCRIPTOR_ELEMENT(&g_wtp.descriptor));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPFRAMETUNNELMODE_ELEMENT(&g_wtp.mactunnel));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPMACTYPE_ELEMENT(&g_wtp.mactype));
|
||||
|
||||
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
||||
for (i = 0; i < g_wtp.radios->count; i++) {
|
||||
struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(&radio->radioinformation));
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Unknown capwap binding");
|
||||
}
|
||||
|
||||
/* CAPWAP_CREATE_MTUDISCOVERYPADDING_ELEMENT */ /* TODO */
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
/* Create discovery request packet */
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
wtp_free_reference_last_request();
|
||||
result = capwap_fragment_build_packet(buildpacket, g_wtp.requestfragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
result = -1;
|
||||
capwap_logging_debug("Warning: build invalid discovery request packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send discovery request to AC */
|
||||
if (result >= 0) {
|
||||
int i;
|
||||
|
||||
/* Send broadcast packet to all socket */
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
int j;
|
||||
struct capwap_packet* packet = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
|
||||
ASSERT(packet != NULL);
|
||||
|
||||
for (j = 0; j < g_wtp.acdiscoveryarray->count; j++) {
|
||||
int sock;
|
||||
struct sockaddr_storage* sendtoaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, j);
|
||||
|
||||
sock = capwap_get_socket(&g_wtp.net, sendtoaddr->ss_family, IPPROTO_UDP, 1);
|
||||
if (sock >= 0) {
|
||||
if (!capwap_sendto(sock, packet->header, packet->packetsize, NULL, sendtoaddr)) {
|
||||
capwap_logging_debug("Warning: error to send discovery request packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't buffering a packets sent */
|
||||
wtp_free_reference_last_request();
|
||||
}
|
||||
|
||||
/* Wait before send another Discovery Request */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDiscoveryInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_discovery_to_sulking(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
capwap_set_timeout(g_wtp.dfa.rfcSilentInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_SULKING_STATE);
|
||||
|
||||
return WTP_DFA_DROP_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_discovery_to_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Retrieve local address */
|
||||
if (!capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
|
||||
wtp_dfa_change_state(CAPWAP_DISCOVERY_TO_SULKING_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
struct sockaddr_storage sockinfo;
|
||||
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
|
||||
|
||||
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
|
||||
if (getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_TO_SULKING_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
|
||||
|
||||
/* */
|
||||
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
|
||||
|
||||
/* */
|
||||
if (!g_wtp.enabledtls) {
|
||||
/* Bypass DTLS connection */
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_TO_JOIN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Create DTLS connection */
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
123
src/wtp/wtp_dfa_dtls.c
Normal file
123
src/wtp/wtp_dfa_dtls.c
Normal file
@ -0,0 +1,123 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* DTLS BIO send */
|
||||
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
|
||||
struct capwap_socket* socket = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrlsock : &g_wtp.acdatasock);
|
||||
struct sockaddr_storage* wtpaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.wtpctrladdress : &g_wtp.wtpdataaddress);
|
||||
struct sockaddr_storage* acaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrladdress : &g_wtp.acdataaddress);
|
||||
|
||||
return capwap_sendto(socket->socket[socket->type], buffer, length, wtpaddress, acaddress);
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Create DTLS session */
|
||||
if (!capwap_crypt_createsession(&g_wtp.ctrldtls, CAPWAP_DTLS_CONTROL_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_TO_IDLE_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
if (capwap_crypt_open(&g_wtp.ctrldtls, &g_wtp.acctrladdress) == CAPWAP_HANDSHAKE_ERROR) {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_TO_IDLE_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_STATE);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcWaitDTLS, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsconnect(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE);
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsconnect_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
||||
|
||||
/* Teardown connection */
|
||||
int wtp_teardown_connection(struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
/* DTSL Control */
|
||||
if (g_wtp.ctrldtls.enable) {
|
||||
capwap_crypt_close(&g_wtp.ctrldtls);
|
||||
}
|
||||
|
||||
/* DTLS Data */
|
||||
if (g_wtp.datadtls.enable) {
|
||||
capwap_crypt_close(&g_wtp.datadtls);
|
||||
}
|
||||
|
||||
/* */
|
||||
capwap_killall_timeout(timeout);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDTLSSessionDelete, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE);
|
||||
return WTP_DFA_DROP_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Free and reset resource */
|
||||
if (g_wtp.ctrldtls.enable) {
|
||||
capwap_crypt_freesession(&g_wtp.ctrldtls);
|
||||
}
|
||||
|
||||
if (g_wtp.datadtls.enable) {
|
||||
capwap_crypt_freesession(&g_wtp.datadtls);
|
||||
}
|
||||
|
||||
/* */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_free_reference_last_response();
|
||||
|
||||
/* */
|
||||
if ((g_wtp.dfa.rfcFailedDTLSSessionCount >= g_wtp.dfa.rfcMaxFailedDTLSSessionRetry) || (g_wtp.dfa.rfcFailedDTLSAuthFailCount >= g_wtp.dfa.rfcMaxFailedDTLSSessionRetry)) {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_TO_SULKING_STATE);
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_TO_IDLE_STATE);
|
||||
}
|
||||
|
||||
/* TODO controllare se <20> richiesto il ravvio del sistema */
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsteardown_to_sulking(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
capwap_set_timeout(g_wtp.dfa.rfcSilentInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_SULKING_STATE);
|
||||
|
||||
return WTP_DFA_DROP_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsteardown_to_idle(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_STATE);
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
92
src/wtp/wtp_dfa_idle.c
Normal file
92
src/wtp/wtp_dfa_idle.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_idle(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
if (!g_wtp.acdiscoveryrequest && (g_wtp.acpreferedarray->count > 0)) {
|
||||
/* Found in configuration file the AC address */
|
||||
memcpy(&g_wtp.acctrladdress, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(struct sockaddr_storage));
|
||||
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage));
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
|
||||
|
||||
/* Configure socket */
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, CAPWAP_CTRL_SOCKET));
|
||||
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acdataaddress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
|
||||
|
||||
/* */
|
||||
g_wtp.acpreferedselected = (g_wtp.acpreferedselected + 1) % g_wtp.acpreferedarray->count;
|
||||
|
||||
/* Connect */
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_TO_DTLS_SETUP_STATE);
|
||||
} else {
|
||||
/* Search AC */
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_TO_DISCOVERY_STATE);
|
||||
}
|
||||
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* Prepare to discovery AC */
|
||||
int wtp_dfa_state_idle_to_discovery(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Set discovery interval */
|
||||
g_wtp.dfa.rfcDiscoveryInterval = capwap_get_rand(g_wtp.dfa.rfcMaxDiscoveryInterval - WTP_MIN_DISCOVERY_INTERVAL) + WTP_MIN_DISCOVERY_INTERVAL;
|
||||
g_wtp.dfa.rfcDiscoveryCount = 0;
|
||||
|
||||
/* Change state */
|
||||
wtp_dfa_change_state(CAPWAP_DISCOVERY_STATE);
|
||||
|
||||
/* Wait before send Discovery Request */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDiscoveryInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
|
||||
return WTP_DFA_DROP_PACKET;
|
||||
}
|
||||
|
||||
/* Prepare to connect with AC */
|
||||
int wtp_dfa_state_idle_to_dtlssetup(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Retrieve local address */
|
||||
if (!capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
struct sockaddr_storage sockinfo;
|
||||
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
|
||||
|
||||
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
|
||||
if (getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_TO_SULKING_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
|
||||
|
||||
/* */
|
||||
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
|
||||
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
|
||||
|
||||
/* */
|
||||
if (!g_wtp.enabledtls) {
|
||||
/* Bypass DTLS connection */
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_CONNECT_TO_JOIN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Create DTLS connection */
|
||||
wtp_dfa_change_state(CAPWAP_DTLS_SETUP_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
11
src/wtp/wtp_dfa_imagedata.c
Normal file
11
src/wtp/wtp_dfa_imagedata.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_imagedata_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
297
src/wtp/wtp_dfa_join.c
Normal file
297
src/wtp/wtp_dfa_join.c
Normal file
@ -0,0 +1,297 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_element.h"
|
||||
#include "capwap_array.h"
|
||||
#include "capwap_list.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
static unsigned long wtp_join_ac(struct capwap_element_join_response* joinresponse) {
|
||||
/* TODO: gestione richiesta
|
||||
CAPWAP_JOIN_TO_IMAGE_DATA_STATE <-> CAPWAP_JOIN_TO_CONFIGURE_STATE
|
||||
*/
|
||||
|
||||
/* Check DTLS data policy */
|
||||
if (!(g_wtp.validdtlsdatapolicy & joinresponse->acdescriptor->dtlspolicy)) {
|
||||
return CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE;
|
||||
}
|
||||
|
||||
/* AC name associated */
|
||||
strcpy(g_wtp.acname.name, joinresponse->acname->name);
|
||||
|
||||
/* DTLS data policy */
|
||||
g_wtp.dtlsdatapolicy = joinresponse->acdescriptor->dtlspolicy & g_wtp.validdtlsdatapolicy;
|
||||
|
||||
return CAPWAP_JOIN_TO_CONFIGURE_STATE;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_dtlsconnect_to_join(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int i;
|
||||
int result = -1;
|
||||
int status = WTP_DFA_NO_PACKET;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
#ifdef DEBUG
|
||||
char sessionname[33];
|
||||
#endif
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Reset DTLS counter */
|
||||
g_wtp.dfa.rfcFailedDTLSSessionCount = 0;
|
||||
|
||||
/* Update status radio */
|
||||
g_wtp.descriptor.radiosinuse = wtp_update_radio_in_use();
|
||||
|
||||
/* Generate session id */
|
||||
capwap_sessionid_generate(&g_wtp.sessionid);
|
||||
|
||||
#ifdef DEBUG
|
||||
capwap_sessionid_printf(&g_wtp.sessionid, sessionname);
|
||||
capwap_logging_debug("Create WTP sessionid: %s", sessionname);
|
||||
#endif
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding);
|
||||
buildpacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare join request */
|
||||
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_JOIN_REQUEST, g_wtp.localseqnumber++);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_LOCATION_ELEMENT(&g_wtp.location));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPBOARDDATA_ELEMENT(&g_wtp.boarddata));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPDESCRIPTOR_ELEMENT(&g_wtp.descriptor));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPNAME_ELEMENT(&g_wtp.name));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_SESSIONID_ELEMENT(&g_wtp.sessionid));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPFRAMETUNNELMODE_ELEMENT(&g_wtp.mactunnel));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPMACTYPE_ELEMENT(&g_wtp.mactype));
|
||||
|
||||
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
||||
for (i = 0; i < g_wtp.radios->count; i++) {
|
||||
struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(&radio->radioinformation));
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Unknown capwap binding");
|
||||
}
|
||||
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_ECNSUPPORT_ELEMENT(&g_wtp.ecn));
|
||||
|
||||
if (g_wtp.wtpctrladdress.ss_family == AF_INET) {
|
||||
struct capwap_localipv4_element addr;
|
||||
|
||||
memcpy(&addr.address, &((struct sockaddr_in*)&g_wtp.wtpctrladdress)->sin_addr, sizeof(struct in_addr));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_LOCALIPV4_ELEMENT(&addr));
|
||||
} else if (g_wtp.wtpctrladdress.ss_family == AF_INET6) {
|
||||
struct capwap_localipv6_element addr;
|
||||
|
||||
memcpy(&addr.address, &((struct sockaddr_in6*)&g_wtp.wtpctrladdress)->sin6_addr, sizeof(struct in6_addr));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_LOCALIPV6_ELEMENT(&addr));
|
||||
}
|
||||
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_TRANSPORT_ELEMENT(&g_wtp.transport));
|
||||
/* CAPWAP_CREATE_MAXIMUMMESSAGELENGTH_ELEMENT */ /* TODO */
|
||||
/* CAPWAP_CREATE_WTPREBOOTSTATISTICS_ELEMENT */ /* TODO */
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
/* Create join request packet */
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
wtp_free_reference_last_request();
|
||||
result = capwap_fragment_build_packet(buildpacket, g_wtp.requestfragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Warning: build invalid join request packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send join request to AC */
|
||||
if (result >= 0) {
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send join request packet");
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
/* Error to send packets */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||||
} else {
|
||||
g_wtp.dfa.rfcRetransmitCount = 0;
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_JOIN_STATE);
|
||||
status = WTP_DFA_ACCEPT_PACKET;
|
||||
}
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_join(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
if (packet) {
|
||||
if (!capwap_compare_ip(&g_wtp.acctrladdress, &packet->remoteaddr)) {
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
/* Parsing packet */
|
||||
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||||
if (buildpacket) {
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
unsigned short binding;
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
if ((binding == g_wtp.binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_JOIN_RESPONSE) && ((g_wtp.localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
|
||||
struct capwap_element_join_response joinresponse;
|
||||
|
||||
/* Valid packet, free request packet */
|
||||
wtp_free_reference_last_request();
|
||||
|
||||
/* Join response info */
|
||||
capwap_init_element_join_response(&joinresponse, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_join_response(&joinresponse, buildpacket->elementslist->first)) {
|
||||
wtp_dfa_change_state(wtp_join_ac(&joinresponse));
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* Free join response */
|
||||
capwap_free_element_join_response(&joinresponse, binding);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
capwap_build_packet_free(buildpacket);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* No Join response received */
|
||||
g_wtp.dfa.rfcRetransmitCount++;
|
||||
if (g_wtp.dfa.rfcRetransmitCount >= g_wtp.dfa.rfcMaxRetransmit) {
|
||||
/* Timeout join state */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Retransmit join request */
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send join request packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update timeout */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_join_to_configure(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
unsigned long i;
|
||||
int result = -1;
|
||||
int status = WTP_DFA_NO_PACKET;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding);
|
||||
buildpacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare Configuration Status request */
|
||||
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_CONFIGURATION_STATUS_REQUEST, g_wtp.localseqnumber++);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_ACNAME_ELEMENT(&g_wtp.acname));
|
||||
|
||||
for (i = 0; i < g_wtp.radios->count; i++) {
|
||||
struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i);
|
||||
struct capwap_radioadmstate_element radioadmstate;
|
||||
|
||||
radioadmstate.radioid = (unsigned char)(i + 1);
|
||||
radioadmstate.state = ((radio->status == WTP_RADIO_DISABLED) ? CAPWAP_RADIO_ADMIN_STATE_DISABLED : CAPWAP_RADIO_ADMIN_STATE_ENABLED);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_RADIOADMSTATE_ELEMENT(&radioadmstate));
|
||||
}
|
||||
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_STATISTICSTIMER_ELEMENT(&g_wtp.statisticstimer));
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_WTPREBOOTSTAT_ELEMENT(&g_wtp.rebootstat));
|
||||
|
||||
/* CAPWAP_CREATE_ACNAMEPRIORITY_ELEMENT */ /* TODO */
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_TRANSPORT_ELEMENT(&g_wtp.transport));
|
||||
/* CAPWAP_CREATE_WTPSTATICIPADDRESS_ELEMENT */ /* TODO */
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
/* Create Configuration Status request packet */
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
wtp_free_reference_last_request();
|
||||
result = capwap_fragment_build_packet(buildpacket, g_wtp.requestfragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Warning: build invalid configuretion status request packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send Configuration Status request to AC */
|
||||
if (result >= 0) {
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send configuration status request packet");
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
/* Error to send packets */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE);
|
||||
} else {
|
||||
g_wtp.dfa.rfcRetransmitCount = 0;
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE);
|
||||
status = WTP_DFA_ACCEPT_PACKET;
|
||||
}
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_join_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
11
src/wtp/wtp_dfa_reset.c
Normal file
11
src/wtp/wtp_dfa_reset.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_reset(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
330
src/wtp/wtp_dfa_run.c
Normal file
330
src/wtp/wtp_dfa_run.c
Normal file
@ -0,0 +1,330 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "capwap_element.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
static int send_echo_request() {
|
||||
int i;
|
||||
int result = -1;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
/* Build packet */
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, g_wtp.binding);
|
||||
buildpacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare echo request */
|
||||
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_ECHO_REQUEST, g_wtp.localseqnumber++);
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
/* Create echo request packet */
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
wtp_free_reference_last_request();
|
||||
result = capwap_fragment_build_packet(buildpacket, g_wtp.requestfragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Warning: build invalid echo request packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send echo request to AC */
|
||||
if (result >= 0) {
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send echo request packet");
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
wtp_free_reference_last_request(); /* Error to send packets */
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int receive_echo_response(struct capwap_build_packet* buildpacket) {
|
||||
unsigned short binding;
|
||||
struct capwap_element_echo_response echoresponse;
|
||||
|
||||
ASSERT(buildpacket != NULL);
|
||||
|
||||
/* Valid packet, free request packet */
|
||||
wtp_free_reference_last_request();
|
||||
|
||||
/* Echo response info */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
capwap_init_element_echo_response(&echoresponse, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_echo_response(&echoresponse, buildpacket->elementslist->first)) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* Free join response */
|
||||
capwap_free_element_echo_response(&echoresponse, binding);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static void receive_reset_request(struct capwap_build_packet* buildpacket, struct capwap_packet* packet) {
|
||||
unsigned long i;
|
||||
unsigned short binding;
|
||||
|
||||
ASSERT(buildpacket != NULL);
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
if ((binding == g_wtp.binding) && IS_SEQUENCE_SMALLER(g_wtp.remoteseqnumber, buildpacket->ctrlmsg.seq)) {
|
||||
struct capwap_element_reset_request resetrequest;
|
||||
|
||||
/* Reset request info*/
|
||||
capwap_init_element_reset_request(&resetrequest, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_reset_request(&resetrequest, buildpacket->elementslist->first)) {
|
||||
struct capwap_build_packet* responsepacket;
|
||||
struct capwap_resultcode_element resultcode = { CAPWAP_RESULTCODE_SUCCESS };
|
||||
|
||||
/* Create response */
|
||||
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
|
||||
responsepacket->isctrlmsg = 1;
|
||||
|
||||
/* Prepare echo response */
|
||||
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_RESET_RESPONSE, buildpacket->ctrlmsg.seq);
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_RESULTCODE_ELEMENT(&resultcode));
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
if (!capwap_build_packet_validate(responsepacket, NULL)) {
|
||||
int result;
|
||||
|
||||
wtp_free_reference_last_response();
|
||||
|
||||
/* Send reset response to AC */
|
||||
result = capwap_fragment_build_packet(responsepacket, g_wtp.responsefragmentpacket, g_wtp.mtu, g_wtp.fragmentid);
|
||||
if (result >= 0) {
|
||||
if (result == 1) {
|
||||
g_wtp.fragmentid++;
|
||||
}
|
||||
|
||||
/* Save remote sequence number */
|
||||
g_wtp.remoteseqnumber = buildpacket->ctrlmsg.seq;
|
||||
capwap_get_packet_digest((void*)packet->header, packet->packetsize, g_wtp.lastrecvpackethash);
|
||||
|
||||
/* Send */
|
||||
for (i = 0; i < g_wtp.responsefragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.responsefragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
|
||||
capwap_logging_debug("Warning: error to send reset response packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
capwap_build_packet_free(responsepacket);
|
||||
}
|
||||
|
||||
/* Free */
|
||||
capwap_free_element_reset_request(&resetrequest, binding);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_run(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
int status = WTP_DFA_ACCEPT_PACKET;
|
||||
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
if (packet) {
|
||||
struct capwap_build_packet* buildpacket;
|
||||
|
||||
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||||
if (buildpacket) {
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
if (packet->socket.isctrlsocket) {
|
||||
unsigned long typemsg = ntohl(buildpacket->ctrlmsg.type);
|
||||
|
||||
if (capwap_is_request_type(typemsg) || ((g_wtp.localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
|
||||
switch (typemsg) {
|
||||
case CAPWAP_CONFIGURATION_UPDATE_RESPONSE: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CHANGE_STATE_EVENT_REQUEST: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_ECHO_RESPONSE: {
|
||||
if (!receive_echo_response(buildpacket)) {
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcEchoInterval, timeout, CAPWAP_TIMER_CONTROL_ECHO);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_CLEAR_CONFIGURATION_RESPONSE: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_WTP_EVENT_REQUEST: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DATA_TRANSFER_REQUEST: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_DATA_TRANSFER_RESPONSE: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case CAPWAP_RESET_REQUEST: {
|
||||
receive_reset_request(buildpacket, packet);
|
||||
wtp_dfa_change_state(CAPWAP_RESET_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IS_FLAG_K_HEADER(&buildpacket->header) && capwap_is_enable_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD)) {
|
||||
struct capwap_sessionid_element sessionid;
|
||||
|
||||
if (capwap_get_sessionid_from_keepalive(buildpacket, &sessionid)) {
|
||||
if (!memcmp(&sessionid, &g_wtp.sessionid, sizeof(struct capwap_sessionid_element))) {
|
||||
/* Receive Data Keep-Alive, wait for next packet */
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDataChannelKeepAlive, timeout, CAPWAP_TIMER_DATA_KEEPALIVE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* TODO */
|
||||
|
||||
/* Update data keep-alive timeout */
|
||||
if (!capwap_is_enable_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD)) {
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDataChannelKeepAlive, timeout, CAPWAP_TIMER_DATA_KEEPALIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
capwap_build_packet_free(buildpacket);
|
||||
}
|
||||
} else {
|
||||
if (capwap_is_timeout(timeout, CAPWAP_TIMER_CONTROL_CONNECTION)) {
|
||||
int i;
|
||||
|
||||
/* No response received */
|
||||
g_wtp.dfa.rfcRetransmitCount++;
|
||||
if (g_wtp.dfa.rfcRetransmitCount >= g_wtp.dfa.rfcMaxRetransmit) {
|
||||
/* Timeout run state */
|
||||
wtp_free_reference_last_request();
|
||||
wtp_dfa_change_state(CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
} else {
|
||||
/* Retransmit request */
|
||||
for (i = 0; i < g_wtp.requestfragmentpacket->count; i++) {
|
||||
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(g_wtp.requestfragmentpacket, i);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
|
||||
capwap_logging_debug("Warning: error to send request packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update timeout */
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
}
|
||||
} else if (capwap_is_timeout(timeout, CAPWAP_TIMER_CONTROL_ECHO)) {
|
||||
/* Disable echo timer */
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_CONTROL_ECHO);
|
||||
|
||||
if (!send_echo_request()) {
|
||||
g_wtp.dfa.rfcRetransmitCount = 0;
|
||||
capwap_set_timeout(g_wtp.dfa.rfcRetransmitInterval, timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
} else if (capwap_is_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVE)) {
|
||||
int result;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
capwap_fragment_packet_array* txfragpacket;
|
||||
|
||||
/* Build packet Data Keep-Alive*/
|
||||
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, CAPWAP_WIRELESS_BINDING_NONE);
|
||||
buildpacket->isctrlmsg = 0;
|
||||
|
||||
/* */
|
||||
SET_FLAG_K_HEADER(&buildpacket->header, 1);
|
||||
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_SESSIONID_ELEMENT(&g_wtp.sessionid));
|
||||
|
||||
txfragpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
|
||||
result = capwap_fragment_build_packet(buildpacket, txfragpacket, CAPWAP_DONT_FRAGMENT, 0);
|
||||
if (!result) {
|
||||
struct capwap_packet* txpacket;
|
||||
|
||||
ASSERT(txfragpacket->count == 1);
|
||||
|
||||
txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(txfragpacket, 0);
|
||||
ASSERT(txpacket != NULL);
|
||||
|
||||
if (!capwap_crypt_sendto(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txpacket->header, txpacket->packetsize, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
|
||||
capwap_logging_debug("Warning: error to send data channel keepalive packet");
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
capwap_fragment_free(txfragpacket);
|
||||
capwap_array_free(txfragpacket);
|
||||
capwap_build_packet_free(buildpacket);
|
||||
|
||||
/* Send Configuration Status request to AC */
|
||||
if (!result) {
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVE);
|
||||
capwap_set_timeout(g_wtp.dfa.rfcDataChannelDeadInterval, timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD);
|
||||
} else {
|
||||
wtp_dfa_change_state(CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
} else if (capwap_is_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD)) {
|
||||
/* Data Keep-Alive timeout */
|
||||
capwap_kill_timeout(timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD);
|
||||
wtp_dfa_change_state(CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
|
||||
status = WTP_DFA_NO_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_run_to_dtlsteardown(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(packet == NULL);
|
||||
ASSERT(timeout != NULL);
|
||||
|
||||
return wtp_teardown_connection(timeout);
|
||||
}
|
27
src/wtp/wtp_dfa_sulking.c
Normal file
27
src/wtp/wtp_dfa_sulking.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include "wtp.h"
|
||||
#include "capwap_dfa.h"
|
||||
#include "wtp_dfa.h"
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_sulking(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
wtp_dfa_change_state(CAPWAP_SULKING_TO_IDLE_STATE);
|
||||
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
||||
|
||||
/* */
|
||||
int wtp_dfa_state_sulking_to_idle(struct capwap_packet* packet, struct timeout_control* timeout) {
|
||||
ASSERT(timeout != NULL);
|
||||
ASSERT(packet == NULL);
|
||||
|
||||
g_wtp.dfa.rfcDiscoveryCount = 0;
|
||||
g_wtp.dfa.rfcFailedDTLSSessionCount = 0;
|
||||
g_wtp.dfa.rfcFailedDTLSAuthFailCount = 0;
|
||||
|
||||
wtp_dfa_change_state(CAPWAP_IDLE_STATE);
|
||||
|
||||
return WTP_DFA_NO_PACKET;
|
||||
}
|
Reference in New Issue
Block a user