The capwap data channel migrated from userspace to kernalspace

This commit is contained in:
vemax78
2014-09-10 21:58:23 +02:00
parent 71006a9121
commit 8d9985fdea
104 changed files with 6967 additions and 4840 deletions

View File

@ -37,9 +37,13 @@ static int ac_init(void) {
/* Network */
capwap_network_init(&g_ac.net);
g_ac.addrlist = capwap_list_create();
g_ac.mtu = CAPWAP_MTU_DEFAULT;
g_ac.binding = capwap_array_create(sizeof(uint16_t), 0, 0);
g_ac.net.bind_sock_ctrl_port = CAPWAP_CONTROL_PORT;
/* Try to use IPv6 */
g_ac.net.localaddr.ss.ss_family = AF_INET6;
CAPWAP_SET_NETWORK_PORT(&g_ac.net.localaddr, CAPWAP_CONTROL_PORT);
/* Standard name */
g_ac.acname.name = (uint8_t*)capwap_duplicate_string(AC_STANDARD_NAME);
@ -134,6 +138,7 @@ static void ac_destroy(void) {
}
capwap_array_free(g_ac.availablebackends);
capwap_list_free(g_ac.addrlist);
}
/* Help */
@ -144,8 +149,6 @@ static void ac_print_usage(void) {
static int ac_parsing_configuration_1_0(config_t* config) {
int i;
int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
config_setting_t* configSetting;
@ -519,7 +522,7 @@ static int ac_parsing_configuration_1_0(config_t* config) {
return 0;
}
strcpy(g_ac.net.bind_interface, configString);
strcpy(g_ac.net.bindiface, configString);
}
/* Set mtu of AC */
@ -532,16 +535,6 @@ static int ac_parsing_configuration_1_0(config_t* config) {
}
}
/* Set network port of WTP */
if (config_lookup_int(config, "application.network.port", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65535)) {
g_ac.net.bind_sock_ctrl_port = (unsigned short)configInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.network.port value");
return 0;
}
}
/* Set transport of AC */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) {
@ -554,35 +547,6 @@ static int ac_parsing_configuration_1_0(config_t* config) {
}
}
/* Set ipv4 & ipv6 of AC */
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_ac.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_ac.net.sock_family = (configIPv4 ? AF_INET : AF_INET6);
}
/* Set ip dual stack of WTP */
if (config_lookup_bool(config, "application.network.ipdualstack", &configBool) == CONFIG_TRUE) {
if (!configBool) {
g_ac.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG;
g_ac.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG;
} else {
g_ac.net.bind_ctrl_flags &= ~CAPWAP_IPV6ONLY_FLAG;
g_ac.net.bind_data_flags &= ~CAPWAP_IPV6ONLY_FLAG;
}
}
/* Backend */
if (config_lookup_string(config, "backend.id", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
@ -754,12 +718,15 @@ static int ac_load_configuration(int argc, char** argv) {
/* Init AC */
static int ac_configure(void) {
/* Bind to any address */
if (!capwap_bind_sockets(&g_ac.net)) {
/* Bind control channel to any address */
if (capwap_bind_sockets(&g_ac.net)) {
capwap_logging_fatal("Cannot bind address");
return AC_ERROR_NETWORK;
}
/* Detect local address */
capwap_interface_list(&g_ac.net, g_ac.addrlist);
return CAPWAP_SUCCESSFUL;
}
@ -834,24 +801,27 @@ int main(int argc, char** argv) {
result = ac_configure();
if (result == CAPWAP_SUCCESSFUL) {
/* Connect AC to kernel module */
value = ac_kmod_init();
if (!value || !g_ac.kmodrequest) {
if (ac_kmod_isconnected()) {
if (!ac_kmod_init(16, 4)) {
/* Bind data channel */
if (!ac_kmod_createdatachannel(g_ac.net.localaddr.ss.ss_family, CAPWAP_GET_NETWORK_PORT(&g_ac.net.localaddr) + 1)) {
capwap_logging_info("SmartCAPWAP kernel module connected");
/* Running AC */
result = ac_execute();
} else {
capwap_logging_fatal("Unable to create kernel data channel");
}
/* Running AC */
result = ac_execute();
/* Close connection */
ac_close();
/* Disconnect kernel module */
ac_kmod_free();
} else {
capwap_logging_fatal("Unable to connect to kernel module");
}
/* Close connection */
ac_close();
}
}
/* Free memory */

View File

@ -61,6 +61,13 @@
#define AC_STATIONS_HASH_SIZE 65536
#define AC_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH
/* */
#define compat_json_object_object_get(obj, key) ({ \
json_bool error; struct json_object* result = NULL; \
error = json_object_object_get_ex(obj, key, &result); \
(error ? result : NULL); \
})
/* */
struct ac_state {
struct capwap_ecnsupport_element ecn;
@ -98,10 +105,9 @@ struct ac_t {
/* */
struct ac_state dfa;
struct capwap_network net;
struct capwap_list* addrlist;
unsigned short mtu;
struct ac_fds fds;
struct capwap_array* binding;
struct capwap_acname_element acname;
@ -111,7 +117,6 @@ struct ac_t {
int fdmsgsessions[2];
/* */
int kmodrequest;
struct ac_kmod_handle kmodhandle;
/* Sessions */

View File

@ -229,7 +229,7 @@ int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, s
struct json_object* jsonradio = json_object_array_get_idx(jsonroot, i);
/* Get RadioID */
jsonitem = json_object_object_get(jsonradio, "RadioID");
jsonitem = compat_json_object_object_get(jsonradio, "RadioID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int radioid = json_object_get_int(jsonitem);
if (IS_VALID_RADIOID(radioid)) {

View File

@ -21,7 +21,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
antenna->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "Diversity");
jsonitem = compat_json_object_object_get(jsonparent, "Diversity");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_boolean)) {
antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE);
} else {
@ -29,7 +29,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "Combiner");
jsonitem = compat_json_object_object_get(jsonparent, "Combiner");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
antenna->combiner = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -37,7 +37,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "AntennaSelection");
jsonitem = compat_json_object_object_get(jsonparent, "AntennaSelection");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_array)) {
int i;
int length;

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
directsequencecontrol->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "CurrentChan");
jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "CurrentCCA");
jsonitem = compat_json_object_object_get(jsonparent, "CurrentCCA");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "EnergyDetectThreshold");
jsonitem = compat_json_object_object_get(jsonparent, "EnergyDetectThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
macoperation->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "RTSThreshold");
jsonitem = compat_json_object_object_get(jsonparent, "RTSThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -30,7 +30,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "ShortRetry");
jsonitem = compat_json_object_object_get(jsonparent, "ShortRetry");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -38,7 +38,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "LongRetry");
jsonitem = compat_json_object_object_get(jsonparent, "LongRetry");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->longretry = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -46,7 +46,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "FragmentationThreshold");
jsonitem = compat_json_object_object_get(jsonparent, "FragmentationThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -54,7 +54,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "TxMSDULifetime");
jsonitem = compat_json_object_object_get(jsonparent, "TxMSDULifetime");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else {
@ -62,7 +62,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "RxMSDULifetime");
jsonitem = compat_json_object_object_get(jsonparent, "RxMSDULifetime");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
multidomaincapability->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "FirstChannel");
jsonitem = compat_json_object_object_get(jsonparent, "FirstChannel");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "NumberChannels");
jsonitem = compat_json_object_object_get(jsonparent, "NumberChannels");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "MaxTxPowerLevel");
jsonitem = compat_json_object_object_get(jsonparent, "MaxTxPowerLevel");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem);
} else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
ofdmcontrol->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "CurrentChan");
jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "BandSupport");
jsonitem = compat_json_object_object_get(jsonparent, "BandSupport");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK;
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "TIThreshold");
jsonitem = compat_json_object_object_get(jsonparent, "TIThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_txpower_createmessageelement(struct json_object* json
txpower->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "CurrentTxPower");
jsonitem = compat_json_object_object_get(jsonparent, "CurrentTxPower");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem);
} else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
wtpradioconf->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "ShortPreamble");
jsonitem = compat_json_object_object_get(jsonparent, "ShortPreamble");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -30,7 +30,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "NumBSSIDs");
jsonitem = compat_json_object_object_get(jsonparent, "NumBSSIDs");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -38,7 +38,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "DTIMPeriod");
jsonitem = compat_json_object_object_get(jsonparent, "DTIMPeriod");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -46,7 +46,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "BSSID");
jsonitem = compat_json_object_object_get(jsonparent, "BSSID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
if (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) {
capwap_free(wtpradioconf);
@ -57,7 +57,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "BeaconPeriod");
jsonitem = compat_json_object_object_get(jsonparent, "BeaconPeriod");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -65,7 +65,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL;
}
jsonitem = json_object_object_get(jsonparent, "CountryString");
jsonitem = compat_json_object_object_get(jsonparent, "CountryString");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* country = json_object_get_string(jsonitem);
if (strlen(country) == (CAPWAP_WTP_RADIO_CONF_COUNTRY_LENGTH - 1)) {

View File

@ -18,7 +18,7 @@ static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_ob
wtpradiofailalarm->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "Type");
jsonitem = compat_json_object_object_get(jsonparent, "Type");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_ob
}
/* */
jsonitem = json_object_object_get(jsonparent, "Status");
jsonitem = compat_json_object_object_get(jsonparent, "Status");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem);
} else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_wtpradioinformation_createmessageelement(struct json_
wtpradioinformation->radioid = radioid;
/* */
jsonitem = json_object_object_get(jsonparent, "Mode");
jsonitem = compat_json_object_object_get(jsonparent, "Mode");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK;
} else {

View File

@ -45,7 +45,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct
*/
/* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId");
jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0;
}
@ -93,19 +93,19 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob
*/
/* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId");
jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0;
}
/* ImageIdentifier */
jsonimage = json_object_object_get(jsonparams, "ImageIdentifier");
jsonimage = compat_json_object_object_get(jsonparams, "ImageIdentifier");
if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) {
return 0;
}
jsonvendor = json_object_object_get(jsonimage, "Vendor");
jsondata = json_object_object_get(jsonimage, "Data");
jsonvendor = compat_json_object_object_get(jsonimage, "Vendor");
jsondata = compat_json_object_object_get(jsonimage, "Data");
if (!jsonvendor || !jsondata || (json_object_get_type(jsonvendor) != json_type_int) || (json_object_get_type(jsondata) != json_type_string)) {
return 0;
}
@ -186,25 +186,25 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
*/
/* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId");
jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0;
}
/* RadioId */
jsonradioid = json_object_object_get(jsonparams, "RadioId");
jsonradioid = compat_json_object_object_get(jsonparams, "RadioId");
if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) {
return 0;
}
/* VirtualAPId */
jsonwlanid = json_object_object_get(jsonparams, "VirtualAPId");
jsonwlanid = compat_json_object_object_get(jsonparams, "VirtualAPId");
if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) {
return 0;
}
/* Capability */
jsoncapability = json_object_object_get(jsonparams, "Capability");
jsoncapability = compat_json_object_object_get(jsonparams, "Capability");
if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) {
return 0;
}
@ -213,37 +213,37 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
/* TODO */
/* DefaultQoS */
jsonqos = json_object_object_get(jsonparams, "DefaultQoS");
jsonqos = compat_json_object_object_get(jsonparams, "DefaultQoS");
if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) {
return 0;
}
/* AuthType */
jsonauthtype = json_object_object_get(jsonparams, "AuthType");
jsonauthtype = compat_json_object_object_get(jsonparams, "AuthType");
if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) {
return 0;
}
/* MACMode */
jsonmacmode = json_object_object_get(jsonparams, "MACMode");
jsonmacmode = compat_json_object_object_get(jsonparams, "MACMode");
if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) {
return 0;
}
/* TunnelMode */
jsontunnelmode = json_object_object_get(jsonparams, "TunnelMode");
jsontunnelmode = compat_json_object_object_get(jsonparams, "TunnelMode");
if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) {
return 0;
}
/* SuppressSSID */
jsonhidessid = json_object_object_get(jsonparams, "SuppressSSID");
jsonhidessid = compat_json_object_object_get(jsonparams, "SuppressSSID");
if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) {
return 0;
}
/* SSID */
jsonssid = json_object_object_get(jsonparams, "SSID");
jsonssid = compat_json_object_object_get(jsonparams, "SSID");
if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) {
ssid = json_object_get_string(jsonssid);
if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) {
@ -386,16 +386,16 @@ static void ac_backend_parsing_event(struct json_object* jsonitem) {
*/
/* Get EventID */
jsonvalue = json_object_object_get(jsonitem, "EventID");
jsonvalue = compat_json_object_object_get(jsonitem, "EventID");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) {
const char* idevent = json_object_get_string(jsonvalue);
/* Get Action */
jsonvalue = json_object_object_get(jsonitem, "Action");
jsonvalue = compat_json_object_object_get(jsonitem, "Action");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) {
const char* action = json_object_get_string(jsonvalue);
if (action) {
jsonvalue = json_object_object_get(jsonitem, "Params");
jsonvalue = compat_json_object_object_get(jsonitem, "Params");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) {
int result = 0;

View File

@ -424,12 +424,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* CAPWAP Timers */
memcpy(&responsetimers, &session->dfa.timers, sizeof(struct capwap_timers_element));
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "CAPWAPTimers");
jsonelement = compat_json_object_object_get(jsonroot, "CAPWAPTimers");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem;
/* Discovery */
jsonitem = json_object_object_get(jsonelement, "Discovery");
jsonitem = compat_json_object_object_get(jsonelement, "Discovery");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) {
@ -438,7 +438,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
}
/* EchoRequest */
jsonitem = json_object_object_get(jsonelement, "EchoRequest");
jsonitem = compat_json_object_object_get(jsonelement, "EchoRequest");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) {
@ -453,7 +453,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* Decryption Error Report Period */
jsonelement = NULL;
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "DecryptionErrorReportPeriod");
jsonelement = compat_json_object_object_get(jsonroot, "DecryptionErrorReportPeriod");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement);
} else {
@ -480,12 +480,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* RadioID */
jsonitem = json_object_object_get(jsonvalue, "RadioID");
jsonitem = compat_json_object_object_get(jsonvalue, "RadioID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256) && ((uint8_t)value == report.radioid)) {
/* Get ReportInterval value */
jsonitem = json_object_object_get(jsonvalue, "ReportInterval");
jsonitem = compat_json_object_object_get(jsonvalue, "ReportInterval");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 65536)) {
@ -506,12 +506,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* IdleTimeout */
memcpy(&responseidletimeout, &session->dfa.idletimeout, sizeof(struct capwap_idletimeout_element));
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "IdleTimeout");
jsonelement = compat_json_object_object_get(jsonroot, "IdleTimeout");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem;
/* Timeout */
jsonitem = json_object_object_get(jsonelement, "Timeout");
jsonitem = compat_json_object_object_get(jsonelement, "Timeout");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
if (value > 0) {
@ -526,12 +526,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* WTPFallback */
memcpy(&responsewtpfallback, &session->dfa.wtpfallback, sizeof(struct capwap_wtpfallback_element));
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "WTPFallback");
jsonelement = compat_json_object_object_get(jsonroot, "WTPFallback");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem;
/* Mode */
jsonitem = json_object_object_get(jsonelement, "Mode");
jsonitem = compat_json_object_object_get(jsonelement, "Mode");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) {
@ -546,7 +546,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* ACIPv4List */
jsonelement = NULL;
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv4List");
jsonelement = compat_json_object_object_get(jsonroot, "ACIPv4List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement);
} else {
@ -567,17 +567,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress");
jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */
if (address.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
if (address.ss.ss_family == AF_INET) {
struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count);
memcpy(responseaddress_in, &address_in->sin_addr, sizeof(struct in_addr));
memcpy(responseaddress_in, &address.sin.sin_addr, sizeof(struct in_addr));
}
}
}
@ -598,7 +597,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* ACIPv6List */
jsonelement = NULL;
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv6List");
jsonelement = compat_json_object_object_get(jsonroot, "ACIPv6List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement);
} else {
@ -619,17 +618,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress");
jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */
if (address.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
if (address.ss.ss_family == AF_INET6) {
struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count);
memcpy(responseaddress_in6, &address_in6->sin6_addr, sizeof(struct in6_addr));
memcpy(responseaddress_in6, &address.sin6.sin6_addr, sizeof(struct in6_addr));
}
}
}
@ -649,43 +647,43 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* WTPStaticIPAddressInformation */
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "WTPStaticIPAddressInformation");
jsonelement = compat_json_object_object_get(jsonroot, "WTPStaticIPAddressInformation");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem;
/* IPAddress */
jsonitem = json_object_object_get(jsonelement, "IPAddress");
jsonitem = compat_json_object_object_get(jsonelement, "IPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage address;
union sockaddr_capwap address;
const char* addressvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(addressvalue, &address)) {
if (address.ss_family == AF_INET) {
if (address.ss.ss_family == AF_INET) {
/* Netmask */
jsonitem = json_object_object_get(jsonelement, "Netmask");
jsonitem = compat_json_object_object_get(jsonelement, "Netmask");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage netmask;
union sockaddr_capwap netmask;
const char* netmaskvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(netmaskvalue, &netmask)) {
if (netmask.ss_family == AF_INET) {
if (netmask.ss.ss_family == AF_INET) {
/* Gateway */
jsonitem = json_object_object_get(jsonelement, "Gateway");
jsonitem = compat_json_object_object_get(jsonelement, "Gateway");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage gateway;
union sockaddr_capwap gateway;
const char* gatewayvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(gatewayvalue, &gateway)) {
if (gateway.ss_family == AF_INET) {
if (gateway.ss.ss_family == AF_INET) {
/* Static */
jsonitem = json_object_object_get(jsonelement, "Static");
jsonitem = compat_json_object_object_get(jsonelement, "Static");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem);
struct capwap_wtpstaticipaddress_element responsewtpstaticipaddress;
memcpy(&responsewtpstaticipaddress.address, &((struct sockaddr_in*)&address)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.netmask, &((struct sockaddr_in*)&netmask)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.gateway, &((struct sockaddr_in*)&gateway)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.address, &address.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.netmask, &netmask.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.gateway, &gateway.sin.sin_addr, sizeof(struct in_addr));
responsewtpstaticipaddress.staticip = (uint8_t)value;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPSTATICIPADDRESS, &responsewtpstaticipaddress);
@ -710,7 +708,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
ac_json_ieee80211_init(&wtpradio);
/* Parsing SOAP response */
jsonelement = json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
jsonelement = compat_json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
if (jsonelement) {
if (ac_json_ieee80211_parsingjson(&wtpradio, jsonelement)) {
/* Add IEEE802.11 message elements to packet */
@ -777,11 +775,11 @@ void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_p
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Configure response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send configuration status response packet");
}
@ -789,7 +787,7 @@ void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_p
/* Change state */
if (CAPWAP_RESULTCODE_OK(result)) {
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_CHANGE_STATE_PENDING_INTERVAL, ac_dfa_state_datacheck_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_CHANGE_STATE_PENDING_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
ac_session_teardown(session);
}

View File

@ -172,11 +172,6 @@ static uint32_t ac_dfa_state_datacheck_create_response(struct ac_session_t* sess
return CAPWAP_RESULTCODE_SUCCESS;
}
/* */
void ac_dfa_state_datacheck_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Configure timeout */
}
/* */
void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
struct ac_soap_response* response;
@ -196,6 +191,13 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
if (response) {
result = ac_dfa_state_datacheck_create_response(session, packet, response, txmngpacket);
ac_soapclient_free_response(response);
/* Create data session */
if (CAPWAP_RESULTCODE_OK(result)) {
if (ac_kmod_new_datasession(&session->sessionid, session->mtu)) {
result = CAPWAP_RESULTCODE_FAILURE;
}
}
}
/* With error add result code message element */
@ -220,11 +222,11 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Change event response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send change event response packet");
}
@ -232,15 +234,9 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
/* Change state */
if (CAPWAP_RESULTCODE_OK(result)) {
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_RUN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DATA_CHECK_INTERVAL, ac_dfa_state_datacheck_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DATA_CHECK_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
ac_session_teardown(session);
}
}
/* */
void ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
ASSERT(session != NULL);
ac_session_teardown(session);
}

View File

@ -3,60 +3,21 @@
#include "capwap_array.h"
#include "ac_session.h"
/* DTLS BIO send */
static int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_session_t* session = (struct ac_session_t*)param;
ASSERT(dtls->session == CAPWAP_DTLS_CONTROL_SESSION);
return capwap_sendto(session->connection.socket.socket[session->connection.socket.type], buffer, length, &session->connection.localaddr, &session->connection.remoteaddr);
}
/* DTLS BIO Data send */
static int ac_bio_data_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param;
ASSERT(dtls->session == CAPWAP_DTLS_DATA_SESSION);
return capwap_sendto(sessiondata->connection.socket.socket[sessiondata->connection.socket.type], buffer, length, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr);
}
/* */
void ac_dtls_setup_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Configure timeout */
}
/* */
int ac_dtls_setup(struct ac_session_t* session) {
ASSERT(session != NULL);
/* Create DTLS session */
if (!capwap_crypt_createsession(&session->dtls, CAPWAP_DTLS_CONTROL_SESSION, &g_ac.dtlscontext, ac_bio_send, session)) {
if (!capwap_crypt_createsession(&session->dtls, &g_ac.dtlscontext)) {
return 0;
}
if (capwap_crypt_open(&session->dtls, &session->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) {
if (capwap_crypt_open(&session->dtls) == CAPWAP_HANDSHAKE_ERROR) {
return 0;
}
/* Wait DTLS handshake complete */
ac_dfa_change_state(session, CAPWAP_DTLS_CONNECT_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DTLS_INTERVAL, ac_dtls_setup_timeout, session, NULL);
return 1;
}
/* */
int ac_dtls_data_setup(struct ac_session_data_t* sessiondata) {
ASSERT(sessiondata != NULL);
/* Create DTLS session */
if (!capwap_crypt_createsession(&sessiondata->dtls, CAPWAP_DTLS_DATA_SESSION, &g_ac.dtlscontext, ac_bio_data_send, sessiondata)) {
return 0;
}
if (capwap_crypt_open(&sessiondata->dtls, &sessiondata->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) {
return 0;
}
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DTLS_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
return 1;
}

View File

@ -403,7 +403,7 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
ac_json_ieee80211_init(&wtpradio);
/* */
jsonelement = json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
jsonelement = compat_json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
if (jsonelement) {
ac_json_ieee80211_parsingjson(&wtpradio, jsonelement);
}
@ -431,13 +431,13 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) {
if (sessioncontrol->localaddress.ss.ss_family == AF_INET) {
struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element);
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) {
} else if (sessioncontrol->localaddress.ss.ss_family == AF_INET6) {
struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
@ -449,22 +449,22 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
capwap_list_free(controllist);
/* CAPWAP Local IP Address */
if (session->connection.localaddr.ss_family == AF_INET) {
if (session->dtls.localaddr.ss.ss_family == AF_INET) {
struct capwap_localipv4_element addr;
memcpy(&addr.address, &((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, sizeof(struct in_addr));
memcpy(&addr.address, &session->dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr);
} else if (session->connection.localaddr.ss_family == AF_INET6) {
} else if (session->dtls.localaddr.ss.ss_family == AF_INET6) {
struct capwap_localipv6_element addr;
memcpy(&addr.address, &((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, sizeof(struct in6_addr));
memcpy(&addr.address, &session->dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr);
}
/* ACIPv4List */
jsonelement = NULL;
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv4List");
jsonelement = compat_json_object_object_get(jsonroot, "ACIPv4List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement);
} else {
@ -484,17 +484,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem;
/* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress");
jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */
if (address.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
if (address.ss.ss_family == AF_INET) {
struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count);
memcpy(responseaddress_in, &address_in->sin_addr, sizeof(struct in_addr));
memcpy(responseaddress_in, &address.sin.sin_addr, sizeof(struct in_addr));
}
}
}
@ -515,7 +514,7 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
/* ACIPv6List */
jsonelement = NULL;
if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv6List");
jsonelement = compat_json_object_object_get(jsonroot, "ACIPv6List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement);
} else {
@ -536,17 +535,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem;
/* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress");
jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */
if (address.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
if (address.ss.ss_family == AF_INET6) {
struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count);
memcpy(responseaddress_in6, &address_in6->sin6_addr, sizeof(struct in6_addr));
memcpy(responseaddress_in6, &address.sin6.sin6_addr, sizeof(struct in6_addr));
}
}
}
@ -578,11 +576,6 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
return CAPWAP_RESULTCODE_SUCCESS;
}
/* */
void ac_dfa_state_join_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Join timeout */
}
/* */
void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
unsigned short binding;
@ -620,6 +613,7 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE;
}
} else {
capwap_logging_info("WTP Id %s already used in another session", wtpid);
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE;
}
@ -628,10 +622,15 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
session->wtpid = wtpid;
memcpy(&session->sessionid, sessionid, sizeof(struct capwap_sessionid_element));
session->binding = binding;
} else {
} else if (wtpid) {
capwap_free(wtpid);
}
} else {
char sessionname[33];
capwap_sessionid_printf(sessionid, sessionname);
capwap_logging_info("Session Id %s already used in another session", sessionname);
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_ID_ALREADY_IN_USE;
}
} else {
@ -668,14 +667,14 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Join response to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
if (CAPWAP_RESULTCODE_OK(resultcode.code)) {
ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
ac_session_teardown(session);
}

View File

@ -51,11 +51,19 @@ static int receive_echo_request(struct ac_session_t* session, struct capwap_pars
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
#ifdef DEBUG
{
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Send Echo Response to %s", sessionname);
}
#endif
/* Send Configure response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send echo response packet");
}
@ -78,7 +86,7 @@ static void execute_ieee80211_wlan_configuration_addwlan(struct ac_session_t* se
wlan = ac_wlans_create_bssid(&session->wlans->devices[assignbssid->radioid - 1], assignbssid->wlanid, assignbssid->bssid, addwlan);
/* Assign BSSID to session */
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_ASSIGN_BSSID, 0, &wlan, sizeof(struct ac_wlan*));
ac_wlans_assign_bssid(session, wlan);
}
}
@ -109,7 +117,7 @@ static void receive_ieee80211_wlan_configuration_response(struct ac_session_t* s
if (CAPWAP_RESULTCODE_OK(resultcode->code)) {
rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket);
if (rxmngrequestpacket) {
if (capwap_parsing_packet(rxmngrequestpacket, NULL, &requestpacket) == PARSING_COMPLETE) {
if (capwap_parsing_packet(rxmngrequestpacket, &requestpacket) == PARSING_COMPLETE) {
/* Detect type of IEEE802.11 WLAN Configuration Request */
if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_80211_ADD_WLAN)) {
execute_ieee80211_wlan_configuration_addwlan(session, packet, &requestpacket);
@ -134,10 +142,10 @@ static void receive_ieee80211_wlan_configuration_response(struct ac_session_t* s
/* */
static void execute_ieee80211_station_configuration_response_addstation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) {
struct ac_wlan* wlan;
struct ac_station* station;
struct capwap_addstation_element* addstation;
struct ac_notify_add_station_status notify;
struct capwap_80211_station_element* station80211;
unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header);
struct capwap_resultcode_element* resultcode;
/* */
@ -145,39 +153,47 @@ static void execute_ieee80211_station_configuration_response_addstation(struct a
addstation = (struct capwap_addstation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_ADDSTATION);
/* */
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (GET_WBID_HEADER(packet->rxmngpacket->header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
station80211 = (struct capwap_80211_station_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_80211_STATION);
if (station80211) {
memset(&notify, 0, sizeof(struct ac_notify_add_station_status));
wlan = ac_wlans_get_bssid_with_wlanid(session, station80211->radioid, station80211->wlanid);
if (wlan) {
station = ac_stations_get_station(session, station80211->radioid, wlan->address, addstation->address);
if (station) {
if (CAPWAP_RESULTCODE_OK(resultcode->code)) {
capwap_logging_info("Authorized station: %s", station->addrtext);
notify.radioid = station80211->radioid;
notify.wlanid = station80211->wlanid;
memcpy(notify.address, addstation->address, MACADDRESS_EUI48_LENGTH);
notify.statuscode = resultcode->code;
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_ADD_STATION_STATUS, 0, (void*)&notify, sizeof(struct ac_notify_add_station_status));
/* */
station->flags |= AC_STATION_FLAGS_AUTHORIZED;
capwap_timeout_deletetimer(session->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} else {
ac_stations_delete_station(session, station);
}
}
}
}
}
}
/* */
static void execute_ieee80211_station_configuration_response_deletestation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) {
struct capwap_deletestation_element* deletestation;
struct ac_notify_delete_station_status notify;
struct ac_station* station;
struct capwap_resultcode_element* resultcode;
struct capwap_deletestation_element* deletestation;
/* */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
deletestation = (struct capwap_deletestation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_DELETESTATION);
/* */
memset(&notify, 0, sizeof(struct ac_notify_delete_station_status));
station = ac_stations_get_station(session, deletestation->radioid, NULL, deletestation->address);
if (station) {
capwap_logging_info("Deauthorized station: %s with %d result code", station->addrtext, (int)resultcode->code);
notify.radioid = deletestation->radioid;
memcpy(notify.address, deletestation->address, MACADDRESS_EUI48_LENGTH);
notify.statuscode = resultcode->code;
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS, 0, (void*)&notify, sizeof(struct ac_notify_delete_station_status));
/* */
ac_stations_delete_station(session, station);
}
}
/* */
@ -187,7 +203,7 @@ static void receive_ieee80211_station_configuration_response(struct ac_session_t
/* Parsing request message */
rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket);
if (capwap_parsing_packet(rxmngrequestpacket, NULL, &requestpacket) == PARSING_COMPLETE) {
if (capwap_parsing_packet(rxmngrequestpacket, &requestpacket) == PARSING_COMPLETE) {
if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_ADDSTATION)) {
execute_ieee80211_station_configuration_response_addstation(session, packet, &requestpacket);
} else if (capwap_get_message_element_data(&requestpacket, CAPWAP_ELEMENT_DELETESTATION)) {
@ -223,6 +239,14 @@ void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet*
}
case CAPWAP_ECHO_REQUEST: {
#ifdef DEBUG
{
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Receive Echo Request from %s", sessionname);
}
#endif
if (!receive_echo_request(session, packet)) {
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {

View File

@ -19,32 +19,32 @@ struct ac_discovery_t {
struct ac_discovery_packet {
int sendsock;
struct sockaddr_storage sender;
union sockaddr_capwap sender;
char data[0];
};
static struct ac_discovery_t g_ac_discovery;
/* */
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender) {
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender) {
struct capwap_list_item* item;
struct ac_discovery_packet* packet;
ASSERT(buffer != NULL);
ASSERT(buffersize > 0);
ASSERT(sock >= 0);
ASSERT(sender != NULL);
/* TODO: mettere un history delle discovery request gi<67> processate per non eseguirle di nuovo */
/* L'elemento deve rimanere per la durata minima di una discovery request */
/* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize);
packet = (struct ac_discovery_packet*)item->item;
packet->sendsock = sock;
memcpy(&packet->sender, sender, sizeof(struct sockaddr_storage));
memcpy(&packet->sender, sender, sizeof(union sockaddr_capwap));
memcpy(packet->data, buffer, buffersize);
/* Append to packets list */
capwap_lock_enter(&g_ac_discovery.packetslock);
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
@ -95,13 +95,13 @@ static struct capwap_packet_txmng* ac_create_discovery_response(struct capwap_pa
for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) {
if (sessioncontrol->localaddress.ss.ss_family == AF_INET) {
struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element);
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) {
} else if (sessioncontrol->localaddress.ss.ss_family == AF_INET6) {
struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
@ -156,12 +156,12 @@ static void ac_discovery_run(void) {
sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet);
/* Accept only discovery request don't fragment */
rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET);
rxmngpacket = capwap_packet_rxmng_create_message();
if (capwap_packet_rxmng_add_recv_packet(rxmngpacket, acpacket->data, sizedata) == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Validate message */
if (capwap_check_message_type(rxmngpacket) == VALID_MESSAGE_TYPE) {
/* Parsing packet */
if (capwap_parsing_packet(rxmngpacket, NULL, &packet) == PARSING_COMPLETE) {
if (capwap_parsing_packet(rxmngpacket, &packet) == PARSING_COMPLETE) {
/* Validate packet */
if (!capwap_validate_parsed_packet(&packet, NULL)) {
struct capwap_packet_txmng* txmngpacket;
@ -185,7 +185,7 @@ static void ac_discovery_run(void) {
capwap_packet_txmng_free(txmngpacket);
/* Send discovery response to WTP */
if (!capwap_sendto_fragmentpacket(acpacket->sendsock, responsefragmentpacket, NULL, &acpacket->sender)) {
if (!capwap_sendto_fragmentpacket(acpacket->sendsock, responsefragmentpacket, &acpacket->sender)) {
capwap_logging_debug("Warning: error to send discovery response packet");
}

View File

@ -3,6 +3,6 @@
int ac_discovery_start(void);
void ac_discovery_stop(void);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender);
#endif /* __AC_DISCOVERY_HEADER__ */

View File

@ -104,7 +104,7 @@ void ac_msgqueue_notify_closethread(pthread_t threadid) {
}
/* */
static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) {
static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) {
int index;
ASSERT(fds);
@ -113,8 +113,7 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct socka
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
ASSERT(fromaddr != NULL);
/* Wait packet */
index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, NULL);
@ -146,7 +145,7 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct socka
}
/* Receive packet */
if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
if (capwap_recvfrom(fds->fdspoll[index].fd, buffer, size, fromaddr, toaddr)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
@ -175,28 +174,6 @@ static void ac_session_add_packet(struct ac_session_t* session, char* buffer, in
capwap_lock_exit(&session->sessionlock);
}
/* Add packet to session data */
static void ac_session_data_add_packet(struct ac_session_data_t* sessiondata, char* buffer, int size, int plainbuffer) {
struct capwap_list_item* item;
struct ac_packet* packet;
ASSERT(sessiondata != NULL);
ASSERT(buffer != NULL);
ASSERT(size > 0);
/* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_packet) + size);
packet = (struct ac_packet*)item->item;
packet->plainbuffer = plainbuffer;
memcpy(packet->buffer, buffer, size);
/* Append to packets list */
capwap_lock_enter(&sessiondata->sessionlock);
capwap_itemlist_insert_after(sessiondata->packets, NULL, item);
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Add action to session */
void ac_session_send_action(struct ac_session_t* session, long action, long param, const void* data, long length) {
struct capwap_list_item* item;
@ -239,52 +216,8 @@ void ac_session_send_action(struct ac_session_t* session, long action, long para
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Add action to session data */
void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length) {
struct capwap_list_item* item;
struct ac_session_action* actionsession;
struct capwap_list_item* search;
ASSERT(sessiondata != NULL);
ASSERT(length >= 0);
/* */
item = capwap_itemlist_create(sizeof(struct ac_session_action) + length);
actionsession = (struct ac_session_action*)item->item;
actionsession->action = action;
actionsession->param = param;
actionsession->length = length;
if (length > 0) {
ASSERT(data != NULL);
memcpy(actionsession->data, data, length);
}
/* Validate session data before use */
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
if (sessiondata == (struct ac_session_data_t*)search->item) {
/* Append to actions list */
capwap_lock_enter(&sessiondata->sessionlock);
capwap_itemlist_insert_after(sessiondata->action, NULL, item);
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
break;
}
/* */
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Find AC sessions */
static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_storage* address) {
static struct ac_session_t* ac_search_session_from_wtpaddress(union sockaddr_capwap* address) {
struct ac_session_t* result = NULL;
struct capwap_list_item* search;
@ -297,7 +230,7 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!capwap_compare_ip(address, &session->connection.remoteaddr)) {
if (!capwap_compare_ip(address, &session->dtls.peeraddr)) {
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
@ -317,40 +250,6 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
return result;
}
/* Find AC sessions data */
static struct ac_session_data_t* ac_search_session_data_from_wtpaddress(struct sockaddr_storage* address) {
struct ac_session_data_t* result = NULL;
struct capwap_list_item* search;
ASSERT(address != NULL);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
ASSERT(sessiondata != NULL);
if (!capwap_compare_ip(address, &sessiondata->connection.remoteaddr)) {
/* Increment session data count */
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count++;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
/* */
result = sessiondata;
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
/* Find session from wtp id */
struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) {
struct ac_session_t* result = NULL;
@ -365,7 +264,41 @@ struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!strcmp(session->wtpid, wtpid)) {
if (session->wtpid && !strcmp(session->wtpid, wtpid)) {
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
capwap_event_signal(&session->changereference);
capwap_lock_exit(&session->sessionlock);
/* */
result = session;
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
/* Find session from wtp id */
struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid) {
struct ac_session_t* result = NULL;
struct capwap_list_item* search;
ASSERT(sessionid != NULL);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
@ -468,14 +401,6 @@ void ac_session_close(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock);
}
/* */
void ac_session_data_close(struct ac_session_data_t* sessiondata) {
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->running = 0;
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Close sessions */
static void ac_close_sessions() {
struct capwap_list_item* search;
@ -493,45 +418,18 @@ static void ac_close_sessions() {
search = search->next;
}
/* Session data */
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
ASSERT(sessiondata != NULL);
ac_session_data_close(sessiondata);
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Detect data channel */
static int ac_is_plain_datachannel(void* buffer, int buffersize) {
struct capwap_preamble* preamble = (struct capwap_preamble*)buffer;
ASSERT(buffer != NULL);
ASSERT(buffersize > sizeof(struct capwap_preamble));
if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED) != 0)) {
return 1;
} else if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) != 0)) {
return 0;
}
return -1;
}
/* Create new session */
static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock) {
static struct ac_session_t* ac_create_session(int sock, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) {
int result;
struct capwap_list_item* itemlist;
struct ac_session_t* session;
ASSERT(acaddress != NULL);
ASSERT(wtpaddress != NULL);
ASSERT(sock != NULL);
ASSERT(sock >= 0);
ASSERT(fromaddr != NULL);
ASSERT(toaddr != NULL);
/* Create new session */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_t));
@ -541,9 +439,8 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
session->itemlist = itemlist;
session->running = 1;
memcpy(&session->connection.socket, sock, sizeof(struct capwap_socket));
memcpy(&session->connection.localaddr, acaddress, sizeof(struct sockaddr_storage));
memcpy(&session->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage));
/* */
capwap_crypt_setconnection(&session->dtls, sock, toaddr, fromaddr);
/* */
ac_wlans_init(session);
@ -555,21 +452,19 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
/* */
session->timeout = capwap_timeout_init();
session->idtimercontrol = capwap_timeout_createtimer(session->timeout);
session->idtimerkeepalivedead = capwap_timeout_createtimer(session->timeout);
/* Duplicate state for DFA */
memcpy(&session->dfa, &g_ac.dfa, sizeof(struct ac_state));
session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses);
session->dfa.acipv6list.addresses = capwap_array_clone(g_ac.dfa.acipv6list.addresses);
/* Add default AC list if empty*/
if ((session->dfa.acipv4list.addresses->count == 0) && (session->dfa.acipv6list.addresses->count == 0)) {
if (acaddress->ss_family == AF_INET) {
struct in_addr* acip = (struct in_addr*)capwap_array_get_item_pointer(session->dfa.acipv4list.addresses, 0);
memcpy(acip, &((struct sockaddr_in*)acaddress)->sin_addr, sizeof(struct in_addr));
} else if (acaddress->ss_family == AF_INET6) {
struct in6_addr* acip = (struct in6_addr*)capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0);
memcpy(acip, &((struct sockaddr_in6*)acaddress)->sin6_addr, sizeof(struct in6_addr));
}
session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses);
if (!session->dfa.acipv4list.addresses->count && (session->dtls.localaddr.ss.ss_family == AF_INET)) {
memcpy(capwap_array_get_item_pointer(session->dfa.acipv4list.addresses, 0), &session->dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
}
session->dfa.acipv6list.addresses = capwap_array_clone(g_ac.dfa.acipv6list.addresses);
if (!session->dfa.acipv6list.addresses->count && (session->dtls.localaddr.ss.ss_family == AF_INET6)) {
memcpy(capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0), &session->dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
}
/* Init */
@ -610,73 +505,6 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
return session;
}
/* Create new session data */
static struct ac_session_data_t* ac_create_session_data(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock, int plain) {
int result;
struct capwap_list_item* itemlist;
struct ac_session_data_t* sessiondata;
ASSERT(acaddress != NULL);
ASSERT(wtpaddress != NULL);
ASSERT(sock != NULL);
/* Create new session data */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_data_t));
sessiondata = (struct ac_session_data_t*)itemlist->item;
memset(sessiondata, 0, sizeof(struct ac_session_data_t));
/* */
sessiondata->itemlist = itemlist;
sessiondata->running = 1;
sessiondata->enabledtls = (plain ? 0 : 1);
/* */
sessiondata->count = 2;
capwap_event_init(&sessiondata->changereference);
/* */
sessiondata->timeout = capwap_timeout_init();
sessiondata->idtimercontrol = capwap_timeout_createtimer(sessiondata->timeout);
sessiondata->idtimerkeepalivedead = capwap_timeout_createtimer(sessiondata->timeout);
/* Connection info */
memcpy(&sessiondata->connection.socket, sock, sizeof(struct capwap_socket));
memcpy(&sessiondata->connection.localaddr, acaddress, sizeof(struct sockaddr_storage));
memcpy(&sessiondata->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage));
sessiondata->mtu = g_ac.mtu;
/* Init */
capwap_event_init(&sessiondata->waitpacket);
capwap_lock_init(&sessiondata->sessionlock);
sessiondata->action = capwap_list_create();
sessiondata->packets = capwap_list_create();
/* Update session data list */
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_insert_after(g_ac.sessionsdata, NULL, itemlist);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Create thread */
result = pthread_create(&sessiondata->threadid, NULL, ac_session_data_thread, (void*)sessiondata);
if (!result) {
struct ac_session_thread_t* sessionthread;
/* Keeps trace of active threads */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_thread_t));
sessionthread = (struct ac_session_thread_t*)itemlist->item;
sessionthread->threadid = sessiondata->threadid;
/* */
capwap_itemlist_insert_after(g_ac.sessionsthread, NULL, itemlist);
} else {
capwap_logging_fatal("Unable create session data thread, error code %d", result);
capwap_exit(CAPWAP_OUT_OF_MEMORY);
}
return sessiondata;
}
/* Release reference of session */
void ac_session_release_reference(struct ac_session_t* session) {
ASSERT(session != NULL);
@ -688,17 +516,6 @@ void ac_session_release_reference(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock);
}
/* Release reference of session data */
void ac_session_data_release_reference(struct ac_session_data_t* sessiondata) {
ASSERT(sessiondata != NULL);
capwap_lock_enter(&sessiondata->sessionlock);
ASSERT(sessiondata->count > 0);
sessiondata->count--;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Update statistics */
void ac_update_statistics(void) {
@ -816,15 +633,17 @@ int ac_execute(void) {
int index;
int check;
struct capwap_socket socket;
struct sockaddr_storage recvfromaddr;
struct sockaddr_storage recvtoaddr;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
struct ac_session_t* session;
char buffer[CAPWAP_MAX_PACKET_SIZE];
int buffersize;
struct ac_fds fds;
/* Set file descriptor pool */
if (ac_execute_init_fdspool(&g_ac.fds, &g_ac.net, g_ac.fdmsgsessions[1]) <= 0) {
if (ac_execute_init_fdspool(&fds, &g_ac.net, g_ac.fdmsgsessions[1]) <= 0) {
capwap_logging_debug("Unable to initialize file descriptor pool");
return AC_ERROR_SYSTEM_FAILER;
}
@ -837,14 +656,14 @@ int ac_execute(void) {
/* Start discovery thread */
if (!ac_discovery_start()) {
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
capwap_logging_debug("Unable to start discovery thread");
return AC_ERROR_SYSTEM_FAILER;
}
/* Enable Backend Management */
if (!ac_backend_start()) {
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
ac_discovery_stop();
capwap_logging_error("Unable start backend management");
return AC_ERROR_SYSTEM_FAILER;
@ -854,7 +673,7 @@ int ac_execute(void) {
while (g_ac.running) {
/* Receive packet */
buffersize = sizeof(buffer);
index = ac_recvfrom(&g_ac.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr);
index = ac_recvfrom(&fds, buffer, &buffersize, &fromaddr, &toaddr);
if (!g_ac.running) {
capwap_logging_debug("Closing AC");
break;
@ -862,119 +681,62 @@ int ac_execute(void) {
/* */
if (index >= 0) {
/* Detect local address */
if (recvtoaddr.ss_family == AF_UNSPEC) {
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_ac.net.bind_interface, (!(g_ac.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
/* Search the AC session */
session = ac_search_session_from_wtpaddress(&fromaddr);
if (session) {
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, 0);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(g_ac.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
/* Release reference */
ac_session_release_reference(session);
} else {
unsigned short sessioncount;
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo));
}
}
/* TODO prevent dos attack add filtering ip for multiple error */
/* Retrieve network information */
capwap_get_network_socket(&g_ac.net, &socket, g_ac.fds.fdspoll[index].fd);
/* Get current session number */
capwap_rwlock_rdlock(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* Search the AC session / session data */
if (socket.isctrlsocket) {
struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr);
/* */
if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) {
check = capwap_sanity_check(CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_header* header = (struct capwap_header*)buffer;
if (session) {
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, 0);
/* Accepted only packet without fragmentation */
if (!IS_FLAG_F_HEADER(header)) {
int headersize = GET_HLEN_HEADER(header) * 4;
if (buffersize >= (headersize + sizeof(struct capwap_control_message))) {
struct capwap_control_message* control = (struct capwap_control_message*)((char*)buffer + headersize);
unsigned long type = ntohl(control->type);
/* Release reference */
ac_session_release_reference(session);
} else {
unsigned short sessioncount;
if (type == CAPWAP_DISCOVERY_REQUEST) {
ac_discovery_add_packet(buffer, buffersize, fds.fdspoll[index].fd, &fromaddr);
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
/* Create a new session */
session = ac_create_session(fds.fdspoll[index].fd, &fromaddr, &toaddr);
ac_session_add_packet(session, buffer, buffersize, 1);
/* TODO prevent dos attack add filtering ip for multiple error */
/* Get current session number */
capwap_rwlock_rdlock(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* */
if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) {
check = capwap_sanity_check(1, CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_header* header = (struct capwap_header*)buffer;
/* Accepted only packet without fragmentation */
if (!IS_FLAG_F_HEADER(header)) {
int headersize = GET_HLEN_HEADER(header) * 4;
if (buffersize >= (headersize + sizeof(struct capwap_control_message))) {
struct capwap_control_message* control = (struct capwap_control_message*)((char*)buffer + headersize);
unsigned long type = ntohl(control->type);
if (type == CAPWAP_DISCOVERY_REQUEST) {
ac_discovery_add_packet(buffer, buffersize, g_ac.fds.fdspoll[index].fd, &recvfromaddr);
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
ac_session_add_packet(session, buffer, buffersize, 1);
/* Release reference */
ac_session_release_reference(session);
}
/* Release reference */
ac_session_release_reference(session);
}
}
} else if (check == CAPWAP_DTLS_PACKET) {
/* Before create new session check if receive DTLS Client Hello */
if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
ac_session_add_packet(session, buffer, buffersize, 0);
/* Release reference */
ac_session_release_reference(session);
}
}
}
}
} else {
struct ac_session_data_t* sessiondata = ac_search_session_data_from_wtpaddress(&recvfromaddr);
} else if (check == CAPWAP_DTLS_PACKET) {
/* Before create new session check if receive DTLS Client Hello */
if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
/* Create a new session */
session = ac_create_session(fds.fdspoll[index].fd, &fromaddr, &toaddr);
ac_session_add_packet(session, buffer, buffersize, 0);
if (sessiondata) {
/* Add packet*/
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
/* Release reference */
ac_session_data_release_reference(sessiondata);
} else {
int plain;
/* TODO prevent dos attack add filtering ip for multiple error */
/* Detect type data channel */
plain = ac_is_plain_datachannel(buffer, buffersize);
/* Before create new session check if receive DTLS Client Hello */
if (!plain) {
if (buffersize <= sizeof(struct capwap_dtls_header)) {
plain = -1;
} else if (!capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
plain = -1;
/* Release reference */
ac_session_release_reference(session);
}
}
/* */
if (plain >= 0) {
/* Create a new session */
sessiondata = ac_create_session_data(&recvfromaddr, &recvtoaddr, &socket, plain);
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
/* Release reference */
ac_session_data_release_reference(sessiondata);
}
}
}
}
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE) || (index == AC_RECV_NOERROR_KMODEVENT)) {
/* Ignore recv */
continue;
@ -1000,6 +762,6 @@ int ac_execute(void) {
ac_backend_free();
/* Free file description pool */
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
return result;
}

View File

@ -3,7 +3,7 @@
#include "ac_wlans.h"
/* */
static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
@ -22,7 +22,7 @@ static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* ses
}
/* */
static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
struct ac_station* station;
@ -36,7 +36,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
/* */
if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_create_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa);
station = ac_stations_create_station(session, radioid, mgmt->bssid, mgmt->sa);
if (!station || !station->wlan) {
return;
}
@ -46,7 +46,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
/* A station is removed if the association does not complete within a given period of time */
station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
station->idtimeout = capwap_timeout_set(sessiondata->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, sessiondata->session);
station->idtimeout = capwap_timeout_set(session->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, session);
/* */
wlan = station->wlan;
@ -94,20 +94,20 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
responselength = ieee80211_create_authentication_response(buffer, sizeof(buffer), &ieee80211_params);
if (responselength > 0) {
/* Send authentication response */
if (!ac_session_data_send_data_packet(sessiondata, wlan->device->radioid, wlan->wlanid, buffer, responselength, 1)) {
if (!ac_kmod_send_data(&session->sockaddrdata.ss, wlan->device->radioid, session->binding, buffer, responselength)) {
capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode);
station->flags |= AC_STATION_FLAGS_AUTHENTICATED;
} else {
capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
}
} else {
capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
}
}
} else if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->da);
station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da);
if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) {
uint16_t algorithm;
uint16_t transactionseqnumber;
@ -135,7 +135,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
}
/* */
static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
struct ac_station* station;
@ -149,7 +149,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Get station */
if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa);
station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->sa);
if (!station || !station->wlan) {
return;
}
@ -162,7 +162,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) {
/* Invalid station, delete station */
capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
return;
}
@ -192,7 +192,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Parsing Information Elements */
if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) {
capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
return;
}
@ -236,19 +236,19 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
responselength = ieee80211_create_associationresponse_response(buffer, sizeof(buffer), &ieee80211_params);
if (responselength > 0) {
/* Send association response */
if (!ac_session_data_send_data_packet(sessiondata, wlan->device->radioid, wlan->wlanid, buffer, responselength, 1)) {
if (!ac_kmod_send_data(&session->sockaddrdata.ss, wlan->device->radioid, session->binding, buffer, responselength)) {
capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode);
/* Active Station */
station->flags |= AC_STATION_FLAGS_ASSOCIATE;
ac_stations_authorize_station(sessiondata->session, station);
ac_stations_authorize_station(session, station);
} else {
capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
}
} else {
capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
}
}
}
@ -256,7 +256,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
}
/* */
static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
struct ac_station* station;
@ -269,7 +269,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
/* Get station */
if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->da);
station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da);
if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) {
capwap_logging_info("Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode);
@ -289,7 +289,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
}
/* Active Station */
ac_stations_authorize_station(sessiondata->session, station);
ac_stations_authorize_station(session, station);
}
}
}
@ -297,7 +297,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
}
/* */
static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
@ -311,7 +311,7 @@ static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_dat
}
/* */
static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
@ -325,7 +325,7 @@ static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_da
}
/* */
static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
struct ieee80211_ie_items ieitems;
@ -339,7 +339,7 @@ static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* se
}
/* */
static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength;
const uint8_t* stationaddress;
struct ac_station* station;
@ -355,19 +355,20 @@ static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t*
stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da);
/* Delete station */
station = ac_stations_get_station(sessiondata->session, radioid, NULL, stationaddress);
station = ac_stations_get_station(session, radioid, NULL, stationaddress);
if (station) {
station->flags &= ~(AC_STATION_FLAGS_AUTHORIZED | AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_stations_delete_station(sessiondata->session, station);
/* Delete station without forward another IEEE802.11 deauthentication message */
station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_stations_delete_station(session, station);
}
}
/* */
static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) {
static void ac_ieee80211_mgmt_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) {
switch (framecontrol_subtype) {
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) {
ac_ieee80211_mgmt_probe_request_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_probe_request_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -375,7 +376,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) {
ac_ieee80211_mgmt_authentication_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_authentication_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -383,7 +384,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) {
ac_ieee80211_mgmt_association_request_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_association_request_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -391,7 +392,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) {
ac_ieee80211_mgmt_association_response_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_association_response_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -399,7 +400,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) {
ac_ieee80211_mgmt_reassociation_request_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_reassociation_request_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -407,7 +408,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse))) {
ac_ieee80211_mgmt_reassociation_response_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_reassociation_response_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -415,7 +416,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) {
ac_ieee80211_mgmt_disassociation_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_disassociation_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -423,7 +424,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) {
ac_ieee80211_mgmt_deauthentication_packet(sessiondata, radioid, mgmt, mgmtlength);
ac_ieee80211_mgmt_deauthentication_packet(session, radioid, mgmt, mgmtlength);
}
break;
@ -436,12 +437,12 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
}
/* */
void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header* header, int length) {
void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length) {
uint16_t framecontrol;
uint16_t framecontrol_type;
uint16_t framecontrol_subtype;
ASSERT(sessiondata != NULL);
ASSERT(session != NULL);
ASSERT(IS_VALID_RADIOID(radioid));
ASSERT(header != NULL);
ASSERT(length >= sizeof(struct ieee80211_header));
@ -453,6 +454,6 @@ void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid,
/* Parsing frame */
if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) {
ac_ieee80211_mgmt_packet(sessiondata, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype);
ac_ieee80211_mgmt_packet(session, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype);
}
}

View File

@ -2,6 +2,7 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include "ac_session.h"
#include "nlsmartcapwap.h"
/* Compatibility functions */
@ -84,8 +85,37 @@ static int ac_kmod_ack_handler(struct nl_msg* msg, void* arg) {
/* */
static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) {
switch (gnlh->cmd) {
default: {
capwap_logging_debug("*** ac_kmod_event_handler: %d", (int)gnlh->cmd);
case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: {
if (tb_msg[NLSMARTCAPWAP_ATTR_ADDRESS] && tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]) {
struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]));
if (session) {
/* Save data channel address */
if (session->sockaddrdata.ss.ss_family == AF_UNSPEC) {
capwap_lock_enter(&session->sessionlock);
memcpy(&session->sockaddrdata.ss, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
capwap_lock_exit(&session->sessionlock);
}
/* Notify keep-alive */
ac_session_send_action(session, AC_SESSION_ACTION_RECV_KEEPALIVE, 0, NULL, 0);
ac_session_release_reference(session);
}
}
break;
}
case NLSMARTCAPWAP_CMD_RECV_DATA: {
if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID] && tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]));
if (session) {
ac_session_send_action(session, AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET, 0, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]));
ac_session_release_reference(session);
}
}
break;
}
}
@ -95,10 +125,10 @@ static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg
/* */
static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) {
struct nlattr* tb_msg[NLSMARTCAPWAP_AC_ATTR_MAX + 1];
struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1];
struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
nla_parse(tb_msg, NLSMARTCAPWAP_AC_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
return ac_kmod_event_handler(gnlh, tb_msg, data);
}
@ -145,7 +175,7 @@ static int ac_kmod_send_and_recv_msg(struct nl_msg* msg, ac_kmod_valid_cb valid_
}
/* */
static int ac_kmod_link(void) {
static int ac_kmod_link(uint32_t hash, uint32_t threads) {
int result;
struct nl_msg* msg;
@ -156,7 +186,9 @@ static int ac_kmod_link(void) {
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_AC_CMD_LINK, 0);
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD, hash);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT, threads);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
@ -188,6 +220,67 @@ static void ac_kmod_event_receive(int fd, void** params, int paramscount) {
}
}
/* */
int ac_kmod_send_keepalive(struct sockaddr_storage* sockaddr) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to send keep-alive: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_send_data(struct sockaddr_storage* sockaddr, uint8_t radioid, uint8_t binding, const uint8_t* data, int length) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
ASSERT(data != NULL);
ASSERT(length > 0);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, binding);
nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, data);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to send data: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_isconnected(void) {
return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0);
@ -222,7 +315,106 @@ int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count) {
}
/* */
int ac_kmod_init(void) {
int ac_kmod_createdatachannel(int family, unsigned short port) {
int result;
struct nl_msg* msg;
struct sockaddr_storage sockaddr;
ASSERT((family == AF_INET) || (family == AF_INET6));
ASSERT(port != 0);
/* */
memset(&sockaddr, 0, sizeof(struct sockaddr_storage));
sockaddr.ss_family = family;
if (sockaddr.ss_family == AF_INET) {
((struct sockaddr_in*)&sockaddr)->sin_port = htons(port);
} else if (sockaddr.ss_family == AF_INET6) {
((struct sockaddr_in6*)&sockaddr)->sin6_port = htons(port);
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to bind kernel socket: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint16_t mtu) {
int result;
struct nl_msg* msg;
ASSERT(sessionid != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_NEW_SESSION, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to create data session: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_delete_datasession(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid) {
int result;
struct nl_msg* msg;
ASSERT(sessionid != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_SESSION, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
if (sockaddr && (sockaddr->ss_family != AF_UNSPEC)) {
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
}
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result && (result != ENOENT)) {
capwap_logging_error("Unable to delete data session: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_init(uint32_t hash, uint32_t threads) {
int result;
/* Configure netlink callback */
@ -242,7 +434,7 @@ int ac_kmod_init(void) {
g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl);
/* Get nlsmartcapwap netlink family */
g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, SMARTCAPWAP_AC_GENL_NAME);
g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME);
if (g_ac.kmodhandle.nlsmartcapwap_id < 0) {
capwap_logging_warning("Unable to found kernel module");
ac_kmod_free();
@ -254,7 +446,7 @@ int ac_kmod_init(void) {
nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL);
/* Link to kernel module */
result = ac_kmod_link();
result = ac_kmod_link(hash, threads);
if (result) {
ac_kmod_free();
return result;

View File

@ -32,11 +32,22 @@ struct ac_kmod_event {
};
/* */
int ac_kmod_init(void);
int ac_kmod_init(uint32_t hash, uint32_t threads);
void ac_kmod_free(void);
/* */
int ac_kmod_isconnected(void);
int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count);
/* */
int ac_kmod_createdatachannel(int family, unsigned short port);
/* */
int ac_kmod_send_keepalive(struct sockaddr_storage* sockaddr);
int ac_kmod_send_data(struct sockaddr_storage* sockaddr, uint8_t radioid, uint8_t binding, const uint8_t* data, int length);
/* */
int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint16_t mtu);
int ac_kmod_delete_datasession(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid);
#endif /* __AC_KMOD_HEADER__ */

View File

@ -6,8 +6,8 @@
#include "ac_backend.h"
#include <arpa/inet.h>
#define AC_ERROR_TIMEOUT -1000
#define AC_ERROR_ACTION_SESSION -1001
#define AC_NO_ERROR -1000
#define AC_ERROR_TIMEOUT -1001
/* */
static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_notify_reset_t* reset) {
@ -39,7 +39,7 @@ static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_no
capwap_packet_txmng_free(txmngpacket);
/* Send Reset Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0;
ac_dfa_change_state(session, CAPWAP_RESET_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
@ -49,7 +49,7 @@ static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_no
ac_session_teardown(session);
}
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
@ -62,10 +62,10 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
/* Check if WLAN id is valid and not used */
if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
#if 0
} else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
#endif
}
@ -102,7 +102,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
capwap_packet_txmng_free(txmngpacket);
/* Send WLAN Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -111,7 +111,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
ac_session_teardown(session);
}
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
@ -125,7 +125,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
/* Check if RADIO id and WLAN id is valid */
if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
@ -167,7 +167,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
capwap_packet_txmng_free(txmngpacket);
/* Send Station Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -176,7 +176,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
ac_session_teardown(session);
}
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
@ -189,7 +189,7 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
/* Check if RADIO id is valid */
if (!IS_VALID_RADIOID(notify->radioid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
@ -216,7 +216,7 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
capwap_packet_txmng_free(txmngpacket);
/* Send Station Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -225,12 +225,25 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
ac_session_teardown(session);
}
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
}
/* */
static int ac_session_action_recv_ieee80211_mgmt_packet(struct ac_session_t* session, struct capwap_header* header, long length) {
long headersize;
/* Retrieve info */
headersize = GET_HLEN_HEADER(header) * 4;
if ((GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) && ((length - headersize) >= sizeof(struct ieee80211_header))) {
ac_ieee80211_packet(session, GET_RID_HEADER(header), (struct ieee80211_header*)(((char*)header) + headersize), (length - headersize));
}
return AC_NO_ERROR;
}
/* */
static int ac_session_action_execute(struct ac_session_t* session, struct ac_session_action* action) {
int result = AC_ERROR_ACTION_SESSION;
int result = AC_NO_ERROR;
switch (action->action) {
case AC_SESSION_ACTION_CLOSE: {
@ -248,24 +261,43 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses
break;
}
case AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA: {
int valid = 0;
struct ac_soap_response* response;
case AC_SESSION_ACTION_RECV_KEEPALIVE: {
#ifdef DEBUG
{
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Receive Keep-Alive from %s", sessionname);
}
#endif
/* Send keep-alive response */
ac_kmod_send_keepalive(&session->sockaddrdata.ss);
capwap_timeout_set(session->timeout, session->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
/* Capwap handshake complete, notify event to backend */
response = ac_soap_runningwtpsession(session, session->wtpid);
if (response) {
valid = ((response->responsecode == HTTP_RESULT_OK) ? 1 : 0);
ac_soapclient_free_response(response);
/* */
if (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) {
struct ac_soap_response* response;
/* Capwap handshake complete, notify event to backend */
response = ac_soap_runningwtpsession(session, session->wtpid);
if (response) {
if (response->responsecode == HTTP_RESULT_OK) {
ac_dfa_change_state(session, CAPWAP_RUN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
result = CAPWAP_ERROR_CLOSE;
}
ac_soapclient_free_response(response);
} else {
result = CAPWAP_ERROR_CLOSE;
}
}
if (valid) {
ac_dfa_change_state(session, CAPWAP_RUN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
result = CAPWAP_ERROR_CLOSE;
}
break;
}
case AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET: {
result = ac_session_action_recv_ieee80211_mgmt_packet(session, (struct capwap_header*)action->data, action->length);
break;
}
@ -289,6 +321,18 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses
result = ac_session_action_station_configuration_ieee8011_delete_station(session, (struct ac_notify_station_configuration_ieee8011_delete_station*)action->data);
break;
}
case AC_SESSION_ACTION_STATION_ROAMING: {
struct ac_station* station;
/* Delete station */
station = ac_stations_get_station(session, RADIOID_ANY, NULL, (uint8_t*)action->data);
if (station) {
ac_stations_delete_station(session, station);
}
break;
}
}
return result;
@ -324,8 +368,6 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
} else if (session->packets->count > 0) {
struct capwap_list_item* itempacket;
capwap_logging_debug("Receive control packet");
/* Get packet */
itempacket = capwap_itemlist_remove_head(session->packets);
capwap_lock_exit(&session->sessionlock);
@ -344,7 +386,7 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (session->dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
if (session->state == CAPWAP_DTLS_CONNECT_STATE) {
ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
}
}
}
@ -420,11 +462,6 @@ static void ac_dfa_execute(struct ac_session_t* session, struct capwap_parsed_pa
break;
}
case CAPWAP_DATA_CHECK_TO_RUN_STATE: {
ac_dfa_state_datacheck_to_run(session, packet);
break;
}
case CAPWAP_RUN_STATE: {
ac_dfa_state_run(session, packet);
break;
@ -472,7 +509,7 @@ static void ac_send_invalid_request(struct ac_session_t* session, uint32_t error
capwap_packet_txmng_free(txmngpacket);
/* Send unknown response */
capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr);
capwap_crypt_sendto_fragmentpacket(&session->dtls, responsefragmentpacket);
/* Don't buffering a packets sent */
capwap_list_free(responsefragmentpacket);
@ -491,12 +528,6 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_logging_debug("Release Session AC %s", sessionname);
#endif
/* Release session data reference */
if (session->sessiondata) {
ac_session_data_close(session->sessiondata);
ac_session_data_release_reference(session->sessiondata);
}
/* Release last reference */
capwap_lock_enter(&session->sessionlock);
session->count--;
@ -523,6 +554,9 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock);
/* Close data channel */
ac_kmod_delete_datasession(&session->sockaddrdata.ss, &session->sessionid);
/* Free DTSL Control */
capwap_crypt_freesession(&session->dtls);
@ -563,38 +597,6 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_itemlist_free(session->itemlist);
}
/* */
static void ac_session_report_connection(struct ac_session_t* session) {
char localip[INET6_ADDRSTRLEN + 10] = "";
char remoteip[INET6_ADDRSTRLEN + 10] = "";
if (session->connection.localaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.localaddr)->sin_port));
} else if (session->connection.localaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.localaddr)->sin6_port));
}
if (session->connection.remoteaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.remoteaddr)->sin_port));
} else if (session->connection.remoteaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_port));
}
capwap_logging_info("Start control channel from %s to %s", remoteip, localip);
}
/* */
static void ac_session_run(struct ac_session_t* session) {
int res;
@ -605,9 +607,6 @@ static void ac_session_run(struct ac_session_t* session) {
ASSERT(session != NULL);
/* */
ac_session_report_connection(session);
/* Configure DFA */
if (g_ac.enabledtls) {
if (!ac_dtls_setup(session)) {
@ -616,7 +615,7 @@ static void ac_session_run(struct ac_session_t* session) {
} else {
/* Wait Join request */
ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
}
while (session->state != CAPWAP_DTLS_TEARDOWN_STATE) {
@ -628,24 +627,31 @@ static void ac_session_run(struct ac_session_t* session) {
}
} else if (length > 0) {
/* Check generic capwap packet */
check = capwap_sanity_check(1, CAPWAP_UNDEF_STATE, buffer, length, 0, 0);
check = capwap_sanity_check(CAPWAP_UNDEF_STATE, buffer, length, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_parsed_packet packet;
/* Defragment management */
if (!session->rxmngpacket) {
session->rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET);
session->rxmngpacket = capwap_packet_rxmng_create_message();
}
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(session->rxmngpacket, buffer, length);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Receive all fragment */
if (!capwap_recv_retrasmitted_request(&session->dtls, session->rxmngpacket, &session->connection, session->lastrecvpackethash, session->responsefragmentpacket)) {
if (capwap_is_request_type(session->rxmngpacket->ctrlmsg.type) && (session->remotetype == session->rxmngpacket->ctrlmsg.type) && (session->remoteseqnumber == session->rxmngpacket->ctrlmsg.seq)) {
/* Retransmit response */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
capwap_logging_error("Error to resend response packet");
} else {
capwap_logging_debug("Retrasmitted control packet");
}
} else {
/* Check message type */
res = capwap_check_message_type(session->rxmngpacket);
if (res == VALID_MESSAGE_TYPE) {
res = capwap_parsing_packet(session->rxmngpacket, &session->connection, &packet);
res = capwap_parsing_packet(session->rxmngpacket, &packet);
if (res == PARSING_COMPLETE) {
int hasrequest = capwap_is_request_type(session->rxmngpacket->ctrlmsg.type);
@ -713,8 +719,6 @@ static void ac_session_run(struct ac_session_t* session) {
ac_send_invalid_request(session, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
}
}
} else {
capwap_logging_debug("Retrasmitted control packet");
}
/* Free memory */
@ -821,9 +825,19 @@ void ac_session_teardown(struct ac_session_t* session) {
}
}
/* Remove timer */
if (session->idtimercontrol != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_unset(session->timeout, session->idtimercontrol);
session->idtimercontrol = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
if (session->idtimerkeepalivedead != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_unset(session->timeout, session->idtimerkeepalivedead);
session->idtimerkeepalivedead = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
/* */
ac_dfa_change_state(session, CAPWAP_DTLS_TEARDOWN_STATE);
capwap_timeout_unset(session->timeout, session->idtimercontrol);
}
/* */
@ -850,53 +864,31 @@ void* ac_session_thread(void* param) {
/* */
void ac_get_control_information(struct capwap_list* controllist) {
struct capwap_list* addrlist;
int count;
struct capwap_list_item* item;
ASSERT(controllist != NULL);
/* Detect local address */
addrlist = capwap_list_create();
capwap_interface_list(&g_ac.net, addrlist);
/* */
capwap_rwlock_rdlock(&g_ac.sessionslock);
count = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* Prepare control list */
for (item = addrlist->first; item != NULL; item = item->next) {
for (item = g_ac.addrlist->first; item != NULL; item = item->next) {
struct capwap_list_item* itemcontrol;
struct ac_session_control* sessioncontrol;
struct sockaddr_storage* address = (struct sockaddr_storage*)item->item;
union sockaddr_capwap* address = (union sockaddr_capwap*)item->item;
/* */
itemcontrol = capwap_itemlist_create(sizeof(struct ac_session_control));
sessioncontrol = (struct ac_session_control*)itemcontrol->item;
memcpy(&sessioncontrol->localaddress, address, sizeof(struct sockaddr_storage));
sessioncontrol->count = 0;
memcpy(&sessioncontrol->localaddress, address, sizeof(union sockaddr_capwap));
sessioncontrol->count = count;
/* Add */
capwap_itemlist_insert_after(controllist, NULL, itemcontrol);
}
/* Free local address list */
capwap_list_free(addrlist);
/* */
capwap_rwlock_rdlock(&g_ac.sessionslock);
/* Get wtp count from any local address */
for (item = controllist->first; item != NULL; item = item->next) {
struct capwap_list_item* search;
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
for (search = g_ac.sessions->first; search != NULL; search = search->next) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
if (!capwap_compare_ip(&session->connection.localaddr, &sessioncontrol->localaddress)) {
sessioncontrol->count++;
}
}
}
/* */
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* */
@ -911,7 +903,8 @@ void ac_free_reference_last_response(struct ac_session_t* session) {
ASSERT(session);
capwap_list_flush(session->responsefragmentpacket);
memset(&session->lastrecvpackethash[0], 0, sizeof(session->lastrecvpackethash));
session->remotetype = 0;
session->remoteseqnumber = 0;
}
/* */
@ -973,17 +966,20 @@ void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long
struct ac_session_t* session = (struct ac_session_t*)context;
if (!session->requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet");
ac_session_teardown(session);
} else {
session->retransmitcount++;
if (session->retransmitcount >= AC_MAX_RETRANSMIT) {
capwap_logging_info("Retransmition request packet timeout");
/* Timeout reset state */
ac_free_reference_last_request(session);
ac_session_teardown(session);
} else {
/* Retransmit Reset Request */
/* Retransmit Request */
capwap_logging_debug("Retransmition request packet");
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) {
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
capwap_logging_error("Error to send request packet");
}
@ -994,5 +990,6 @@ void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long
}
void ac_dfa_teardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_info("Session timeout, teardown");
ac_session_teardown((struct ac_session_t*)context);
}

View File

@ -15,23 +15,23 @@ struct ac_packet {
/* */
struct ac_session_control {
struct sockaddr_storage localaddress;
union sockaddr_capwap localaddress;
unsigned short count;
};
/* */
#define AC_SESSION_ACTION_CLOSE 0
#define AC_SESSION_ACTION_RESET_WTP 1
#define AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA 2
#define AC_SESSION_ACTION_NOTIFY_EVENT 3
#define AC_SESSION_ACTION_ADDWLAN 4
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION 5
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION 6
#define AC_SESSION_ACTION_NOTIFY_EVENT 2
#define AC_SESSION_DATA_ACTION_ROAMING_STATION 1
#define AC_SESSION_DATA_ACTION_ASSIGN_BSSID 2
#define AC_SESSION_DATA_ACTION_ADD_STATION_STATUS 3
#define AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS 4
#define AC_SESSION_ACTION_RECV_KEEPALIVE 10
#define AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET 11
#define AC_SESSION_ACTION_ADDWLAN 20
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION 30
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION 31
#define AC_SESSION_ACTION_STATION_ROAMING 32
/* */
struct ac_session_action {
@ -94,56 +94,8 @@ struct ac_notify_station_configuration_ieee8011_delete_station {
uint8_t address[MACADDRESS_EUI48_LENGTH];
};
/* */
struct ac_notify_add_station_status {
uint8_t radioid;
uint8_t wlanid;
uint8_t address[MACADDRESS_EUI48_LENGTH];
uint16_t statuscode;
};
/* */
struct ac_notify_delete_station_status {
uint8_t radioid;
uint8_t address[MACADDRESS_EUI48_LENGTH];
uint16_t statuscode;
};
/* */
struct ac_session_t;
struct ac_session_data_t;
/* AC sessions data */
struct ac_session_data_t {
int running;
pthread_t threadid;
struct capwap_list_item* itemlist; /* My itemlist into g_ac.sessionsdata */
/* Reference */
long count;
capwap_event_t changereference;
/* */
int enabledtls;
unsigned short mtu;
unsigned short fragmentid;
struct capwap_connection connection;
struct capwap_dtls dtls;
struct capwap_timeout* timeout;
unsigned long idtimercontrol;
unsigned long idtimerkeepalivedead;
capwap_event_t waitpacket;
capwap_lock_t sessionlock;
struct capwap_list* action;
struct capwap_list* packets;
struct capwap_packet_rxmng* rxmngpacket;
struct ac_session_t* session;
struct capwap_sessionid_element sessionid;
};
/* AC sessions */
struct ac_session_t {
@ -166,17 +118,18 @@ struct ac_session_t {
unsigned long state;
struct ac_state dfa;
/* */
unsigned short binding;
struct ac_session_data_t* sessiondata;
struct capwap_sessionid_element sessionid;
int teardown;
unsigned short mtu;
struct capwap_dtls dtls;
struct capwap_connection connection;
union sockaddr_capwap sockaddrdata;
struct capwap_timeout* timeout;
unsigned long idtimercontrol;
unsigned long idtimerkeepalivedead;
capwap_event_t waitpacket;
capwap_lock_t sessionlock;
@ -185,14 +138,16 @@ struct ac_session_t {
struct capwap_list* notifyevent;
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;
uint8_t localseqnumber;
struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount;
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
};
/* Session */
@ -202,21 +157,13 @@ void ac_session_teardown(struct ac_session_t* session);
void ac_session_close(struct ac_session_t* session);
void ac_session_release_reference(struct ac_session_t* session);
/* Session data */
void* ac_session_data_thread(void* param);
void ac_session_data_close(struct ac_session_data_t* sessiondata);
void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length);
void ac_session_data_release_reference(struct ac_session_data_t* sessiondata);
int ac_session_data_send_data_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe);
/* IEEE802.11 Packet */
void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header* header, int length);
/* */
struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid);
int ac_has_sessionid(struct capwap_sessionid_element* sessionid);
/* */
int ac_has_sessionid(struct capwap_sessionid_element* sessionid);
int ac_has_wtpid(const char* wtpid);
struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid);
int ac_has_wtpid(const char* wtpid);
/* */
char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata);
@ -231,6 +178,9 @@ void ac_get_control_information(struct capwap_list* controllist);
void ac_free_reference_last_request(struct ac_session_t* session);
void ac_free_reference_last_response(struct ac_session_t* session);
/* */
void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length);
/* */
int ac_msgqueue_init(void);
void ac_msgqueue_free(void);
@ -238,8 +188,6 @@ void ac_msgqueue_notify_closethread(pthread_t threadid);
/* */
int ac_dtls_setup(struct ac_session_t* session);
int ac_dtls_data_setup(struct ac_session_data_t* sessiondata);
void ac_dtls_setup_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
/* */
void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
@ -248,20 +196,11 @@ void ac_dfa_teardown_timeout(struct capwap_timeout* timeout, unsigned long index
/* */
void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_join_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_imagedata(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_reset(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_teardown(struct ac_session_t* session);
/* Soap function */

View File

@ -1,527 +0,0 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "ac_session.h"
#include "ac_wlans.h"
#include "ieee80211.h"
#include <arpa/inet.h>
#define AC_ERROR_TIMEOUT -1000
#define AC_ERROR_ACTION_SESSION -1001
#define AC_BODY_PACKET_MAX_SIZE 8192
/* */
static int ac_session_data_action_add_station_status(struct ac_session_data_t* sessiondata, struct ac_notify_add_station_status* notify) {
struct ac_wlan* wlan;
struct ac_station* station;
wlan = ac_wlans_get_bssid_with_wlanid(sessiondata->session, notify->radioid, notify->wlanid);
if (wlan) {
station = ac_stations_get_station(sessiondata->session, notify->radioid, wlan->address, notify->address);
if (station) {
if (CAPWAP_RESULTCODE_OK(notify->statuscode)) {
capwap_logging_info("Authorized station: %s", station->addrtext);
/* */
station->flags |= AC_STATION_FLAGS_AUTHORIZED;
capwap_timeout_deletetimer(sessiondata->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} else {
ac_stations_delete_station(sessiondata->session, station);
}
}
}
return AC_ERROR_ACTION_SESSION;
}
/* */
static int ac_session_data_action_delete_station_status(struct ac_session_data_t* sessiondata, struct ac_notify_delete_station_status* notify) {
struct ac_station* station;
station = ac_stations_get_station(sessiondata->session, notify->radioid, NULL, notify->address);
if (station) {
capwap_logging_info("Deauthorized station: %s with %d result code", station->addrtext, (int)notify->statuscode);
/* */
ac_stations_delete_station(sessiondata->session, station);
}
return AC_ERROR_ACTION_SESSION;
}
/* */
static int ac_session_data_action_execute(struct ac_session_data_t* sessiondata, struct ac_session_action* action) {
int result = AC_ERROR_ACTION_SESSION;
switch (action->action) {
case AC_SESSION_DATA_ACTION_ROAMING_STATION: {
struct ac_station* station;
/* Delete station */
station = ac_stations_get_station(sessiondata->session, RADIOID_ANY, NULL, (uint8_t*)action->data);
if (station) {
ac_stations_delete_station(sessiondata->session, station);
}
break;
}
case AC_SESSION_DATA_ACTION_ASSIGN_BSSID: {
ac_wlans_assign_bssid(sessiondata->session, *(struct ac_wlan**)action->data);
break;
}
case AC_SESSION_DATA_ACTION_ADD_STATION_STATUS: {
result = ac_session_data_action_add_station_status(sessiondata, (struct ac_notify_add_station_status*)action->data);
break;
}
case AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS: {
result = ac_session_data_action_delete_station_status(sessiondata, (struct ac_notify_delete_station_status*)action->data);
break;
}
}
return result;
}
/* */
static int ac_network_read(struct ac_session_data_t* sessiondata, void* buffer, int length) {
long waittimeout;
int result = CAPWAP_ERROR_AGAIN;
ASSERT(sessiondata != NULL);
ASSERT(buffer != NULL);
ASSERT(length > 0);
for (;;) {
capwap_lock_enter(&sessiondata->sessionlock);
if (!sessiondata->running) {
capwap_lock_exit(&sessiondata->sessionlock);
return CAPWAP_ERROR_CLOSE;
} else if (sessiondata->action->count > 0) {
struct capwap_list_item* itemaction;
itemaction = capwap_itemlist_remove_head(sessiondata->action);
capwap_lock_exit(&sessiondata->sessionlock);
/* */
result = ac_session_data_action_execute(sessiondata, (struct ac_session_action*)itemaction->item);
/* Free packet */
capwap_itemlist_free(itemaction);
return result;
} else if (sessiondata->packets->count > 0) {
struct capwap_list_item* itempacket;
capwap_logging_debug("Receive data packet");
/* Get packet */
itempacket = capwap_itemlist_remove_head(sessiondata->packets);
capwap_lock_exit(&sessiondata->sessionlock);
if (itempacket) {
struct ac_packet* packet = (struct ac_packet*)itempacket->item;
long packetlength = itempacket->itemsize - sizeof(struct ac_packet);
if (!packet->plainbuffer && sessiondata->dtls.enable) {
int oldaction = sessiondata->dtls.action;
result = capwap_decrypt_packet(&sessiondata->dtls, packet->buffer, packetlength, buffer, length);
if (result == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (sessiondata->dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
capwap_timeout_unset(sessiondata->timeout, sessiondata->idtimercontrol);
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
}
}
} else {
if (packetlength <= length) {
memcpy(buffer, packet->buffer, packetlength);
result = packetlength;
}
}
/* Free packet */
capwap_itemlist_free(itempacket);
}
return result;
}
capwap_lock_exit(&sessiondata->sessionlock);
/* Get timeout */
waittimeout = capwap_timeout_getcoming(sessiondata->timeout);
if (!waittimeout) {
capwap_timeout_hasexpired(sessiondata->timeout);
return AC_ERROR_TIMEOUT;
}
/* Wait packet */
capwap_event_wait_timeout(&sessiondata->waitpacket, waittimeout);
}
return result;
}
/* Management keep-alive */
static int ac_session_data_keepalive(struct ac_session_data_t* sessiondata, struct capwap_parsed_packet* packet) {
int result = 0;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
struct capwap_sessionid_element* sessionid;
/* Get session id */
sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID);
if (!sessionid) {
return 0;
}
/* */
if (sessiondata->session) {
if (memcmp(sessionid, &sessiondata->sessionid, sizeof(struct capwap_sessionid_element))) {
return 0; /* Invalid session id */
}
} else {
struct capwap_list_item* search;
/* Retrieve session and interconnect with session data */
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
/* Link session and session data */
capwap_lock_enter(&session->sessionlock);
session->count++;
sessiondata->session = session;
capwap_event_signal(&session->changereference);
capwap_lock_exit(&session->sessionlock);
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count++;
session->sessiondata = sessiondata;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
/* */
if (sessiondata->session) {
#ifdef DEBUG
char sessionname[33];
capwap_sessionid_printf(sessionid, sessionname);
capwap_logging_debug("Establiched Session Data AC %s", sessionname);
#endif
/* Notify established session data */
memcpy(&sessiondata->sessionid, sessionid, sizeof(struct capwap_sessionid_element));
ac_session_send_action(sessiondata->session, AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA, 0, NULL, 0);
} else {
return 0; /* Session not found */
}
}
/* Send keep-alive response */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(packet->rxmngpacket->header));
capwap_header_set_keepalive_flag(&capwapheader, 1);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, sessiondata->mtu);
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &sessiondata->sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, sessiondata->fragmentid);
if (txfragpacket->count == 1) {
/* Send Data keepalive to WTP */
if (capwap_crypt_sendto_fragmentpacket(&sessiondata->dtls, sessiondata->connection.socket.socket[sessiondata->connection.socket.type], txfragpacket, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr)) {
result = 1;
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet");
}
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet");
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}
/* Release reference of session data */
static void ac_session_data_destroy(struct ac_session_data_t* sessiondata) {
#ifdef DEBUG
char sessionname[33];
#endif
ASSERT(sessiondata != NULL);
#ifdef DEBUG
capwap_sessionid_printf(&sessiondata->sessionid, sessionname);
capwap_logging_debug("Release Session Data AC %s", sessionname);
#endif
/* Remove session data from list */
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_remove(g_ac.sessionsdata, sessiondata->itemlist);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Release session reference */
if (sessiondata->session) {
ac_session_close(sessiondata->session);
ac_session_release_reference(sessiondata->session);
}
/* Release last reference */
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count--;
/* Check if all reference is release */
while (sessiondata->count > 0) {
#ifdef DEBUG
capwap_logging_debug("Wait for release Session Data AC %s (count=%d)", sessionname, sessiondata->count);
#endif
/* */
capwap_event_reset(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
/* Wait */
capwap_event_wait(&sessiondata->changereference);
capwap_lock_enter(&sessiondata->sessionlock);
}
capwap_lock_exit(&sessiondata->sessionlock);
/* Free DTLS */
capwap_crypt_freesession(&sessiondata->dtls);
/* Free resource */
while (sessiondata->packets->count > 0) {
capwap_itemlist_free(capwap_itemlist_remove_head(sessiondata->packets));
}
/* */
capwap_event_destroy(&sessiondata->changereference);
capwap_event_destroy(&sessiondata->waitpacket);
capwap_lock_destroy(&sessiondata->sessionlock);
capwap_list_free(sessiondata->action);
capwap_list_free(sessiondata->packets);
capwap_timeout_free(sessiondata->timeout);
/* Free fragments packet */
if (sessiondata->rxmngpacket) {
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
}
/* Free item */
capwap_itemlist_free(sessiondata->itemlist);
}
/* */
static void ac_session_data_report_connection(struct ac_session_data_t* sessiondata) {
char localip[INET6_ADDRSTRLEN + 10] = "";
char remoteip[INET6_ADDRSTRLEN + 10] = "";
if (sessiondata->connection.localaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_port));
} else if (sessiondata->connection.localaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_port));
}
if (sessiondata->connection.remoteaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_port));
} else if (sessiondata->connection.remoteaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_port));
}
capwap_logging_info("Start data channel from %s to %s", remoteip, localip);
}
/* */
static void ac_session_data_run(struct ac_session_data_t* sessiondata) {
int res;
int check;
int length;
struct capwap_connection connection;
char buffer[CAPWAP_MAX_PACKET_SIZE];
uint8_t radioid;
unsigned short binding;
int bodypacketlength;
uint8_t bodypacket[AC_BODY_PACKET_MAX_SIZE];
ASSERT(sessiondata != NULL);
/* */
ac_session_data_report_connection(sessiondata);
/* Create DTLS channel */
if (sessiondata->enabledtls) {
if (ac_dtls_data_setup(sessiondata)) {
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimercontrol, AC_DTLS_INTERVAL, NULL, NULL, NULL);
} else {
capwap_logging_debug("Unable to start DTLS data");
sessiondata->running = 0;
}
} else {
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
}
/* */
while (sessiondata->running) {
/* Get packet */
length = ac_network_read(sessiondata, buffer, sizeof(buffer));
if (length < 0) {
if ((length == CAPWAP_ERROR_SHUTDOWN) || (length == CAPWAP_ERROR_CLOSE)) {
break; /* Close Session Data */
}
} else if (length > 0) {
/* Check generic capwap packet */
check = capwap_sanity_check(0, CAPWAP_UNDEF_STATE, buffer, length, 0, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_parsed_packet packet;
/* Defragment management */
if (!sessiondata->rxmngpacket) {
sessiondata->rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_DATA_PACKET);
}
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(sessiondata->rxmngpacket, buffer, length);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Validate message */
if (capwap_check_message_type(sessiondata->rxmngpacket) == VALID_MESSAGE_TYPE) {
/* Parsing packet */
res = capwap_parsing_packet(sessiondata->rxmngpacket, &connection, &packet);
if (res == PARSING_COMPLETE) {
/* Validate packet */
if (!capwap_validate_parsed_packet(&packet, NULL)) {
if (IS_FLAG_K_HEADER(packet.rxmngpacket->header)) {
ac_session_data_keepalive(sessiondata, &packet);
/* Update timeout */
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
} else {
bodypacketlength = capwap_packet_getdata(sessiondata->rxmngpacket, bodypacket, AC_BODY_PACKET_MAX_SIZE);
/* Parsing body packet */
if (bodypacketlength > 0) {
radioid = GET_RID_HEADER(sessiondata->rxmngpacket->header);
binding = GET_WBID_HEADER(sessiondata->rxmngpacket->header);
if ((binding == CAPWAP_WIRELESS_BINDING_IEEE80211) && (bodypacketlength >= sizeof(struct ieee80211_header))) {
ac_ieee80211_packet(sessiondata, radioid, (struct ieee80211_header*)bodypacket, bodypacketlength);
}
}
}
} else {
capwap_logging_debug("Failed validation parsed data packet");
}
} else {
capwap_logging_debug("Failed parsing data packet");
}
}
/* Free memory */
capwap_free_parsed_packet(&packet);
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
sessiondata->rxmngpacket = NULL;
} else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) {
/* Discard fragments */
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
sessiondata->rxmngpacket = NULL;
}
}
}
}
/* Release reference session data */
ac_session_data_destroy(sessiondata);
}
/* */
void* ac_session_data_thread(void* param) {
pthread_t threadid;
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param;
ASSERT(param != NULL);
threadid = sessiondata->threadid;
/* */
capwap_logging_debug("Session data start");
ac_session_data_run(sessiondata);
capwap_logging_debug("Session data end");
/* Notify terminate thread */
ac_msgqueue_notify_closethread(threadid);
/* Thread exit */
pthread_exit(NULL);
return NULL;
}
/* */
int ac_session_data_send_data_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe) {
int result = 0;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
capwap_header_init(&capwapheader, radioid, sessiondata->session->binding);
capwap_header_set_nativeframe_flag(&capwapheader, (leavenativeframe ? 1: 0));
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, sessiondata->mtu);
/* */
if (leavenativeframe) {
capwap_packet_txmng_add_data(txmngpacket, data, length);
} else {
/* TODO */
}
/* Data message complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, sessiondata->fragmentid);
if (txfragpacket->count > 1) {
sessiondata->fragmentid++;
}
/* */
if (!capwap_crypt_sendto_fragmentpacket(&sessiondata->dtls, sessiondata->connection.socket.socket[sessiondata->connection.socket.type], txfragpacket, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr)) {
capwap_logging_debug("Warning: error to send data packet");
result = -1;
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}

View File

@ -567,7 +567,7 @@ struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_reques
httprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_TIMEOUT;
/* Create socket */
httprequest->sock = socket(httprequest->server->address.ss_family, SOCK_STREAM, 0);
httprequest->sock = socket(httprequest->server->address.ss.ss_family, SOCK_STREAM, 0);
if (httprequest->sock < 0) {
ac_soapclient_close_request(httprequest, 0);
return NULL;

View File

@ -21,7 +21,7 @@
/* */
struct ac_http_soap_server {
int protocol;
struct sockaddr_storage address;
union sockaddr_capwap address;
char* host;
char* path;

View File

@ -42,7 +42,7 @@ static void ac_stations_reset_station(struct ac_session_t* session, struct ac_st
/* Remove timers */
if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_deletetimer(session->sessiondata->timeout, station->idtimeout);
capwap_timeout_deletetimer(session->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
@ -153,7 +153,6 @@ int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) {
/* */
wlan->session = session;
wlan->sessiondata = session->sessiondata;
/* Create WLAN list */
if (!session->wlans->devices[wlan->device->radioid - 1].wlans) {
@ -354,7 +353,7 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint
if (ownersession != session) {
/* Release station from old owner */
if (ownersession) {
ac_session_data_send_action(ownersession->sessiondata, AC_SESSION_DATA_ACTION_ROAMING_STATION, 0, (void*)address, MACADDRESS_EUI48_LENGTH);
ac_session_send_action(ownersession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH);
}
/* Set station into Global Cache Stations List */
@ -411,7 +410,7 @@ void ac_stations_authorize_station(struct ac_session_t* session, struct ac_stati
ASSERT(session->wlans != NULL);
ASSERT(station != NULL);
/* Active Station only if Authenticated, Associated and not Authrizated */
/* Active Station only if Authenticated, Associated and not Authorizated */
if ((station->flags & AC_STATION_FLAGS_AUTHENTICATED) && (station->flags & AC_STATION_FLAGS_ASSOCIATE) && !(station->flags & AC_STATION_FLAGS_AUTHORIZED)) {
memset(&notify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station));
notify.radioid = station->wlan->device->radioid;
@ -457,7 +456,7 @@ void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_sta
responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params);
if (responselength > 0) {
station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_session_data_send_data_packet(session->sessiondata, station->wlan->device->radioid, station->wlan->wlanid, buffer, responselength, 1);
ac_kmod_send_data(&session->sockaddrdata.ss, station->wlan->device->radioid, session->binding, buffer, responselength);
}
}
}

View File

@ -20,7 +20,6 @@ struct ac_wlan {
/* CAPWAP Session */
struct ac_session_t* session;
struct ac_session_data_t* sessiondata;
uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE];

View File

@ -4,7 +4,10 @@ obj-m += smartcapwap.o
smartcapwap-y := \
main.o \
netlinkapp.o
netlinkapp.o \
capwap.o \
capwap_private.o \
socket.o
all:
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules

621
src/ac/kmod/capwap.c Normal file
View File

@ -0,0 +1,621 @@
#include "config.h"
#include <linux/module.h>
#include <linux/ieee80211.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
#define TIMEOUT_PACKET 10
/* */
union capwap_addr sc_localaddr;
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
TRACEKMOD("### sc_capwap_fragment_free\n");
/* */
list_del(&fragment->lru_list);
fragment->flags = 0;
/* Free socket buffer */
while (fragment->fragments) {
struct sk_buff* next = fragment->fragments->next;
kfree_skb(fragment->fragments);
fragment->fragments = next;
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
unsigned long flags;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_defrag_evictor\n");
/* */
if (now.tv64 == 0) {
TRACEKMOD("*** Get time\n");
now = ktime_get();
}
/* Remove last old fragment */
if (!list_empty(&session->fragments.lru_list)) {
spin_lock_irqsave(&session->fragments.lock, flags);
fragment = list_first_entry(&session->fragments.lru_list, struct sc_capwap_fragment, lru_list);
if (fragment) {
delta = ktime_sub(now, fragment->tstamp);
if ((delta.tv64 < 0) || (delta.tv64 > NSEC_PER_SEC)) {
TRACEKMOD("*** Expired fragment %hu\n", fragment->fragmentid);
/* Reset fragment */
sc_capwap_fragment_free(fragment);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
}
}
/* */
static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) {
int len;
int offset;
struct sk_buff* skb;
struct sk_buff* skbfrag;
struct sc_capwap_header* header;
/* */
skbfrag = fragment->fragments;
len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
/* Create new packet */
skb = alloc_skb(len + fragment->totallength, GFP_KERNEL);
if (!skb) {
return NULL;
}
/* The first capwap header is header of reassembled packet without fragment field */
header = (struct sc_capwap_header*)skb_put(skb, len);
memcpy(header, skb->data, len);
SET_FLAG_F_HEADER(header, 0);
SET_FLAG_L_HEADER(header, 0);
header->frag_id = (__be16)0;
header->frag_off = (__be16)0;
/* Copy body */
while (skbfrag) {
offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
len = skb->len - offset;
/* */
memcpy(skb_put(skb, len), skb->data + offset, len);
skbfrag = skbfrag->next;
}
return skb;
}
/* */
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
unsigned long flags;
uint16_t headersize;
uint16_t frag_id;
struct sk_buff* prev;
struct sk_buff* next;
struct sc_capwap_fragment* fragment;
struct sc_skb_capwap_cb* cb;
struct sk_buff* skb_defrag = NULL;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_defrag\n");
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if (skb->len < headersize) {
goto error;
}
/* */
frag_id = be16_to_cpu(header->frag_id);
/* */
cb = CAPWAP_SKB_CB(skb);
cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT;
cb->frag_offset = be16_to_cpu(header->frag_off);
cb->frag_length = skb->len - headersize;
/* */
spin_lock_irqsave(&session->fragments.lock, flags);
/* Get fragment */
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) {
goto error2; /* Queue fragment busy*/
}
/* Init fragment */
if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) {
fragment->flags = CAPWAP_FRAGMENT_ENABLE;
fragment->fragmentid = frag_id;
fragment->fragments = NULL;
fragment->lastfragment = NULL;
fragment->recvlength = 0;
fragment->totallength = 0;
list_add_tail(&fragment->lru_list, &session->fragments.lru_list);
}
/* Search fragment position */
prev = fragment->lastfragment;
if (!prev) {
next = NULL;
} else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) {
if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) < cb->frag_offset) {
next = NULL;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
} else {
prev = NULL;
for (next = fragment->fragments; next != NULL; next = next->next) {
struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next);
if (next_cb->frag_offset < cb->frag_offset) {
if ((next_cb->frag_offset + next_cb->frag_length) < cb->frag_offset) {
break;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
}
prev = next;
}
}
/* Insert fragment */
skb->prev = NULL;
skb->next = next;
if (!next) {
fragment->lastfragment = skb;
}
if (prev) {
prev->next = skb;
} else {
fragment->fragments = skb;
}
/* Update size */
fragment->recvlength += cb->frag_length;
if (IS_FLAG_L_HEADER(header)) {
fragment->totallength = cb->frag_offset + cb->frag_length;
fragment->flags |= CAPWAP_FRAGMENT_LAST;
}
/* Check if receive all fragment */
if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) {
skb_defrag = sc_capwap_reasm(fragment);
/* Free fragment complete */
sc_capwap_fragment_free(fragment);
} else {
/* Update timeout */
fragment->tstamp = skb->tstamp;
if (fragment->tstamp.tv64 == 0) {
fragment->tstamp = ktime_get();
}
/* Set LRU timeout */
if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) {
list_move_tail(&fragment->lru_list, &session->fragments.lru_list);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
return skb_defrag;
error2:
spin_unlock_irqrestore(&session->fragments.lock, flags);
error:
kfree_skb(skb);
return NULL;
}
/* */
int sc_capwap_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_capwap_bind\n");
/* */
ret = sc_socket_bind(sockaddr);
if (ret) {
return ret;
}
memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr));
return 0;
}
/* */
void sc_capwap_initsession(struct sc_capwap_session* session) {
TRACEKMOD("### sc_capwap_initsession\n");
INIT_LIST_HEAD(&session->list);
spin_lock_init(&session->fragmentid_lock);
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
}
/* */
void sc_capwap_freesession(struct sc_capwap_session* session) {
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
}
/* */
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
uint16_t fragmentid;
unsigned long flags;
TRACEKMOD("### sc_capwap_newfragmentid\n");
spin_lock_irqsave(&session->fragmentid_lock, flags);
fragmentid = session->fragmentid++;
spin_unlock_irqrestore(&session->fragmentid_lock, flags);
return fragmentid;
}
/* */
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) {
int length;
struct sc_capwap_header* header;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* msgelement;
TRACEKMOD("### sc_capwap_createkeepalive\n");
/* */
if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) {
return -ENOMEM;
}
/* Preamble CAPWAP header */
header = (struct sc_capwap_header*)buffer;
length = sizeof(struct sc_capwap_header);
buffer += sizeof(struct sc_capwap_header);
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4);
SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211);
SET_FLAG_K_HEADER(header, 1);
/* CAPWAP Data header */
dataheader = (struct sc_capwap_data_message*)buffer;
length += sizeof(struct sc_capwap_data_message);
buffer += sizeof(struct sc_capwap_data_message);
dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element));
/* CAPWAP Keep-Alive Message Element */
msgelement = (struct sc_capwap_message_element*)buffer;
length += sizeof(struct sc_capwap_message_element);
buffer += sizeof(struct sc_capwap_message_element);
msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID);
msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element));
/* Session ID */
memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element));
length += sizeof(struct sc_capwap_sessionid_element);
return length;
}
/* */
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) {
int length;
uint16_t headersize;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* message;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_parsingpacket\n");
/* Linearize socket buffer */
if (skb_linearize(skb)) {
TRACEKMOD("*** Unable to linearize packet\n");
return -EINVAL;
}
/* Check header */
if (skb->len < sizeof(struct sc_capwap_header)) {
TRACEKMOD("*** Invalid capwap header length\n");
return -EINVAL;
} else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) {
TRACEKMOD("*** Invalid capwap header version\n");
return -EINVAL;
} else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) {
TRACEKMOD("*** Packet is encrypted\n");
return -EINVAL; /* Accept only plain packet */
}
/* Cleaning old fragments */
if (session) {
sc_capwap_defrag_evictor(session, skb->tstamp);
}
/* */
if (IS_FLAG_K_HEADER(header)) {
/* Keep alive can not fragment */
if (IS_FLAG_F_HEADER(header)) {
TRACEKMOD("*** Keep alive can not fragment\n");
return -EINVAL;
}
/* */
length = skb->len;
headersize = GET_HLEN_HEADER(header) * 4;
if (length < (headersize + sizeof(struct sc_capwap_data_message))) {
TRACEKMOD("*** Invalid capwap data header length\n");
return -EINVAL;
}
/* Data message */
length -= headersize;
dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize);
headersize = ntohs(dataheader->length);
if (length < headersize) {
TRACEKMOD("*** Capwap data header length mismatch\n");
return -EINVAL;
}
/* Message elements */
headersize -= sizeof(struct sc_capwap_data_message);
message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message));
while (headersize > 0) {
uint16_t msglength = ntohs(message->length);
if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) {
TRACEKMOD("*** Invalid capwap message element length\n");
return -EINVAL;
}
/* */
if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) {
struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element));
if (!session) {
session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid);
if (!session) {
TRACEKMOD("*** Receive unknown keep alive without valid session\n");
return -EINVAL;
}
} else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
TRACEKMOD("*** Session id mismatch\n");
return -EINVAL;
}
/* Session found */
sc_netlink_notify_recv_keepalive(sockaddr, sessionid);
/* Parsing complete */
kfree_skb(skb);
return 0;
}
/* Next message element */
msglength += sizeof(struct sc_capwap_message_element);
message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength);
headersize -= msglength;
}
} else if (session) {
if (IS_FLAG_F_HEADER(header)) {
skb = sc_capwap_defrag(session, skb);
if (!skb) {
return 0;
}
/* Get new header info */
header = (struct sc_capwap_header*)skb->data;
}
/* Parsing data/management packet */
if (!IS_FLAG_T_HEADER(header)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4);
if (ieee80211_is_data_present(hdr->frame_control)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) {
sc_capwap_parsingmgmtpacket(session, skb);
}
}
/* Parsing complete */
kfree_skb(skb);
return 0;
}
return -EINVAL;
}
/* */
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) {
int size;
int length;
int reserve;
int headroom;
int requestfragment;
__be16 fragmentid = 0;
int fragmentoffset = 0;
struct sc_capwap_header* header;
struct sk_buff* clone = NULL;
int packetlength = skb->len;
TRACEKMOD("### sc_capwap_forwarddata\n");
/* Check headroom */
headroom = skb_headroom(skb);
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
printk("*** Expand socket buffer\n");
clone = skb_copy_expand(skb, max_t(int, headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
if (!clone) {
printk("*** Unable to expand socket buffer\n");
return -ENOMEM;
}
skb = clone;
}
/* Check MTU */
requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0);
if (requestfragment) {
fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session));
}
/* */
header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength);
while (packetlength > 0) {
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_WBID_HEADER(header, binding);
SET_RID_HEADER(header, radioid);
SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1));
if (!fragmentoffset) {
uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header);
if (radioaddr) {
SET_FLAG_M_HEADER(header, 1);
memcpy(headeroption, radioaddr, radioaddrlength);
headeroption += radioaddrlength;
}
if (winfo) {
SET_FLAG_W_HEADER(header, 1);
memcpy(headeroption, winfo, winfolength);
headeroption += winfolength;
}
size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
SET_HLEN_HEADER(header, size / 4);
} else {
size = sizeof(struct sc_capwap_header);
SET_HLEN_HEADER(header, size / 4);
}
/* Calculate body size */
length = session->mtu - size;
if (packetlength <= length) {
length = packetlength;
} else if (requestfragment) {
length -= length % 8; /* Capwap fragment size is module 8 */
} else {
break;
}
/* Fragment options */
if (requestfragment) {
SET_FLAG_F_HEADER(header, 1);
if (packetlength == length) {
SET_FLAG_L_HEADER(header, 1);
}
header->frag_id = fragmentid;
header->frag_off = cpu_to_be16(fragmentoffset);
}
/* Send packet */
if (sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr) < 0) {
break;
}
/* */
header = (struct sc_capwap_header*)((uint8_t*)header + (size + length));
fragmentoffset += length;
packetlength -= length;
}
if (clone) {
kfree_skb(clone);
}
return (!packetlength ? 0 : -EIO);
}
/* */
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) {
int i;
char* pos = string;
for (i = 0; i < 16; i++) {
snprintf(pos, 3, "%02x", sessionid->id[i]);
pos += 2;
}
*pos = 0;
}
/* */
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) {
struct sc_capwap_radio_addr* radioaddr;
struct sc_capwap_macaddress_eui48* addr;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
radioaddr = (struct sc_capwap_radio_addr*)buffer;
radioaddr->length = MACADDRESS_EUI48_LENGTH;
addr = (struct sc_capwap_macaddress_eui48*)(buffer + sizeof(struct sc_capwap_radio_addr));
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
return radioaddr;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) {
struct sc_capwap_wireless_information* winfo;
struct sc_capwap_ieee80211_frame_info* frameinfo;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
winfo = (struct sc_capwap_wireless_information*)buffer;
winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info);
frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information));
frameinfo->rssi = rssi;
frameinfo->snr = snr;
frameinfo->rate = cpu_to_be16(rate);
return winfo;
}

128
src/ac/kmod/capwap.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
#define MAX_MTU 9000
#define DEFAULT_MTU 1450
#define MIN_MTU 500
#define IEEE80211_MTU 7981
/* */
#define CAPWAP_FRAGMENT_QUEUE 16
/* */
#define CAPWAP_FRAGMENT_ENABLE 0x0001
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
#define CAPWAP_FRAGMENT_LAST 0x0004
/* */
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0004
#define SKB_CAPWAP_FLAG_PEERADDRESS 0x0010
#define SKB_CAPWAP_FLAG_RADIOID 0x0020
#define SKB_CAPWAP_FLAG_BINDING 0x0040
#define SKB_CAPWAP_FLAG_RADIOADDRESS 0x0080
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0100
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
struct sc_skb_capwap_cb {
uint16_t flags;
struct capwap_addr_little peeraddr;
/* Capwap information */
uint8_t radioid;
uint8_t binding;
/* Radio Address */
uint8_t radioaddr_addr[MACADDRESS_EUI48_LENGTH];
/* Wireless Information */
uint8_t winfo_rssi;
uint8_t winfo_snr;
uint16_t winfo_rate;
/* Fragment */
uint16_t frag_offset;
uint16_t frag_length;
};
#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb))
/* */
struct sc_capwap_fragment {
struct list_head lru_list;
uint8_t flags;
ktime_t tstamp;
uint16_t fragmentid;
struct sk_buff* fragments;
struct sk_buff* lastfragment;
int recvlength;
int totallength;
};
/* */
struct sc_capwap_fragment_queue {
spinlock_t lock;
struct list_head lru_list;
struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE];
};
/* */
struct sc_capwap_session {
struct list_head list;
struct sc_capwap_session* __rcu next;
uint16_t mtu;
union capwap_addr peeraddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t fragmentid;
spinlock_t fragmentid_lock;
struct sc_capwap_fragment_queue fragments;
};
/* */
extern union capwap_addr sc_localaddr;
/* Dipendent implementation function */
void sc_capwap_recvpacket(struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb);
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(union capwap_addr* sockaddr);
void sc_capwap_initsession(struct sc_capwap_session* session);
void sc_capwap_freesession(struct sc_capwap_session* session);
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
struct sc_capwap_packet* sc_capwap_poppacketqueue(struct sc_capwap_session* session);
void sc_capwap_pushpacketqueue(struct sc_capwap_session* session, struct sc_capwap_packet* packet);
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength);
/* Private funciotn */
#include "capwap_private.h"
#endif /* __KMOD_CAPWAP_HEADER__ */

View File

@ -0,0 +1,636 @@
#include "config.h"
#include <linux/module.h>
#include <linux/hash.h>
#include <linux/kthread.h>
#include <net/ipv6.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* Sessions */
static struct mutex sc_wtpsession_mutex;
static struct list_head sc_wtpsession_list;
static struct list_head sc_wtpsession_setup_list;
static uint32_t sc_wtpsession_size;
static uint32_t sc_wtpsession_size_shift;
static struct sc_capwap_session** __rcu sc_wtpsession_hash;
/* Threads */
static DEFINE_SPINLOCK(sc_wtpsession_threads_lock);
static uint32_t sc_wtpsession_threads_pos;
static uint32_t sc_wtpsession_threads_count;
static struct sc_capwap_workthread* sc_wtpsession_threads;
/* */
static uint32_t sc_capwap_hash(const union capwap_addr* peeraddr) {
TRACEKMOD("### sc_capwap_hash\n");
return hash_32(((peeraddr->ss.ss_family == AF_INET) ? peeraddr->sin.sin_addr.s_addr : ipv6_addr_hash(&peeraddr->sin6.sin6_addr)), sc_wtpsession_size_shift);
}
/* */
static void sc_capwap_closewtpsession(struct sc_capwap_session* wtpsession) {
TRACEKMOD("### sc_capwap_closewtpsession\n");
lockdep_assert_held(&sc_wtpsession_mutex);
/* Remove session from list reference */
if (wtpsession->peeraddr.ss.ss_family != AF_UNSPEC) {
uint32_t hash = sc_capwap_hash(&wtpsession->peeraddr);
struct sc_capwap_session* search = rcu_dereference_protected(sc_wtpsession_hash[hash], lockdep_is_held(&sc_wtpsession_mutex));
if (search) {
if (search == wtpsession) {
rcu_assign_pointer(sc_wtpsession_hash[hash], wtpsession->next);
} else {
while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != wtpsession)) {
search = rcu_dereference_protected(search->next, lockdep_is_held(&sc_wtpsession_mutex));
}
if (rcu_access_pointer(search->next)) {
rcu_assign_pointer(search->next, wtpsession->next);
}
}
}
}
/* */
list_del_rcu(&wtpsession->list);
synchronize_net();
/* Free memory */
sc_capwap_freesession(wtpsession);
kfree(wtpsession);
TRACEKMOD("*** Free session\n");
}
/* */
static void sc_capwap_closewtpsessions(void) {
struct sc_capwap_session* wtpsession;
struct sc_capwap_session* temp;
TRACEKMOD("### sc_capwap_closewtpsessions\n");
TRACEKMOD("*** Delete all sessions\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
/* */
list_for_each_entry_safe(wtpsession, temp, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete setup session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
}
/* */
list_for_each_entry_safe(wtpsession, temp, &sc_wtpsession_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete running session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
}
/* */
synchronize_net();
mutex_unlock(&sc_wtpsession_mutex);
}
/* */
static int sc_capwap_deletesetupsession(const struct sc_capwap_sessionid_element* sessionid) {
int ret = -ENOENT;
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deletesetupsession\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
list_for_each_entry(wtpsession, &sc_wtpsession_setup_list, list) {
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete setup session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
ret = 0;
break;
}
}
/* */
mutex_unlock(&sc_wtpsession_mutex);
return ret;
}
/* */
static int sc_capwap_deleterunningsession(const union capwap_addr* peeraddr) {
int ret = -ENOENT;
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deleterunningsession\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
/* Search session with address hash */
wtpsession = sc_capwap_getsession(peeraddr);
if (wtpsession) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete running session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
ret = 0;
}
/* */
mutex_unlock(&sc_wtpsession_mutex);
return ret;
}
/* */
static int sc_capwap_thread_recvpacket(struct sk_buff* skb) {
int ret = 1;
union capwap_addr peeraddr;
struct sc_capwap_session* session;
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_capwap_thread_recvpacket\n");
/* */
if (cb->flags & SKB_CAPWAP_FLAG_FROM_USER_SPACE) {
TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_USER_SPACE\n");
/* Get peer address */
sc_addr_fromlittle(&cb->peeraddr, &peeraddr);
TRACEKMOD("*** Address %d %x %x\n", peeraddr.ss.ss_family, (int)peeraddr.sin.sin_addr.s_addr, (int)peeraddr.sin.sin_port);
/* Send packet*/
rcu_read_lock();
session = sc_capwap_getsession(&peeraddr);
if (session) {
if (sc_capwap_forwarddata(session, cb->radioid, cb->binding, skb, 0, NULL, 0, NULL, 0)) {
TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n");
}
} else {
TRACEKMOD("*** Unable to find session\n");
}
rcu_read_unlock();
} else if (cb->flags & SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL) {
TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL\n");
/* Get peer address */
if (sc_socket_getpeeraddr(skb, &peeraddr)) {
TRACEKMOD("*** Unable get address from packet\n");
return -EINVAL;
}
/* Remove UDP header */
if (!skb_pull(skb, sizeof(struct udphdr))) {
TRACEKMOD("*** Invalid packet\n");
return -EOVERFLOW;
}
/* */
rcu_read_lock();
session = sc_capwap_getsession(&peeraddr);
ret = sc_capwap_parsingpacket(session, &peeraddr, skb);
rcu_read_unlock();
}
return ret;
}
/* */
static int sc_capwap_thread(void* data) {
struct sk_buff* skb;
struct sc_capwap_workthread* thread = (struct sc_capwap_workthread*)data;
TRACEKMOD("### sc_capwap_thread\n");
TRACEKMOD("*** Thread start\n");
for (;;) {
wait_event_interruptible(thread->waitevent, (skb_queue_len(&thread->queue) > 0) || kthread_should_stop());
if (kthread_should_stop()) {
break;
}
/* Get packet */
skb = skb_dequeue(&thread->queue);
if (!skb) {
continue;
}
/* */
TRACEKMOD("*** Thread receive packet\n");
if (sc_capwap_thread_recvpacket(skb)) {
TRACEKMOD("*** Free packet\n");
kfree_skb(skb);
}
}
TRACEKMOD("*** Thread end\n");
return 0;
}
/* */
int sc_capwap_sendkeepalive(const union capwap_addr* peeraddr) {
int ret;
int length;
struct sc_capwap_session* session;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
TRACEKMOD("### sc_capwap_sendkeepalive\n");
/* */
rcu_read_lock();
/* Get session */
session = sc_capwap_getsession(peeraddr);
if (!session) {
TRACEKMOD("*** Unknown keep-alive session\n");
ret = -ENOENT;
goto done;
}
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&session->sessionid, sessionname);
TRACEKMOD("*** Send keep-alive session: %s\n", sessionname);
} while(0);
#endif
/* Build keepalive */
length = sc_capwap_createkeepalive(&session->sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_socket_send(SOCKET_UDP, buffer, length, &session->peeraddr);
if (ret > 0) {
ret = 0;
}
done:
rcu_read_unlock();
return ret;
}
/* */
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) {
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_newsession\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Create session: %s\n", sessionname);
} while(0);
#endif
/* */
session = kzalloc(sizeof(struct sc_capwap_session), GFP_KERNEL);
if (!session) {
TRACEKMOD("*** Unable to create session\n");
return -ENOMEM;
}
/* Initialize session */
sc_capwap_initsession(session);
memcpy(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
session->mtu = mtu;
/* Add to setup session list */
mutex_lock(&sc_wtpsession_mutex);
list_add_rcu(&session->list, &sc_wtpsession_setup_list);
mutex_unlock(&sc_wtpsession_mutex);
TRACEKMOD("*** Create session\n");
return 0;
}
/* */
int sc_capwap_init(uint32_t hash, uint32_t threads) {
uint32_t i;
int err = -ENOMEM;
TRACEKMOD("### sc_capwap_init\n");
TRACEKMOD("*** Init capwap module - hash bitfield: %u - threads: %u\n", hash, threads);
/* Init session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
mutex_init(&sc_wtpsession_mutex);
INIT_LIST_HEAD(&sc_wtpsession_list);
INIT_LIST_HEAD(&sc_wtpsession_setup_list);
sc_wtpsession_size_shift = hash;
sc_wtpsession_size = 1 << hash;
sc_wtpsession_hash = (struct sc_capwap_session**)kzalloc(sizeof(struct sc_capwap_session*) * sc_wtpsession_size, GFP_KERNEL);
if (!sc_wtpsession_hash) {
goto error;
}
/* Create threads */
sc_wtpsession_threads_pos = 0;
sc_wtpsession_threads_count = threads;
sc_wtpsession_threads = (struct sc_capwap_workthread*)kzalloc(sizeof(struct sc_capwap_workthread) * threads, GFP_KERNEL);
if (!sc_wtpsession_threads) {
goto error2;
}
for (i = 0; i < threads; i++) {
sc_wtpsession_threads[i].thread = kthread_create(sc_capwap_thread, &sc_wtpsession_threads[i], "smartcapwap/%u", i);
if (IS_ERR(sc_wtpsession_threads[i].thread)) {
err = PTR_ERR(sc_wtpsession_threads[i].thread);
sc_wtpsession_threads[i].thread = NULL;
goto error3;
}
}
/* Init sockect */
err = sc_socket_init();
if (err) {
goto error3;
}
/* Start threads */
for (i = 0; i < threads; i++) {
skb_queue_head_init(&sc_wtpsession_threads[i].queue);
init_waitqueue_head(&sc_wtpsession_threads[i].waitevent);
wake_up_process(sc_wtpsession_threads[i].thread);
}
return 0;
error3:
for (i = 0; i < threads; i++) {
if (sc_wtpsession_threads[i].thread) {
kthread_stop(sc_wtpsession_threads[i].thread);
}
}
kfree(sc_wtpsession_threads);
error2:
kfree(sc_wtpsession_hash);
error:
return err;
}
/* */
void sc_capwap_close(void) {
uint32_t i;
TRACEKMOD("### sc_capwap_close\n");
TRACEKMOD("*** Closing capwap module\n");
sc_socket_close();
/* */
for (i = 0; i < sc_wtpsession_threads_count; i++) {
kthread_stop(sc_wtpsession_threads[i].thread);
}
kfree(sc_wtpsession_threads);
/* */
sc_capwap_closewtpsessions();
mutex_destroy(&sc_wtpsession_mutex);
kfree(sc_wtpsession_hash);
TRACEKMOD("*** Close capwap module\n");
}
/* */
int sc_capwap_deletesession(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) {
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deletesession\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Delete session: %s\n", sessionname);
} while(0);
#endif
/* Searching item with read lock */
rcu_read_lock();
/* Search into running session list */
if (sockaddr && sc_capwap_getsession(sockaddr)) {
rcu_read_unlock();
/* Remove session with address */
return sc_capwap_deleterunningsession(sockaddr);
} else {
list_for_each_entry_rcu(wtpsession, &sc_wtpsession_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Check running session for delete: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
union capwap_addr peeraddr;
/* Get peer address */
memcpy(&peeraddr, &wtpsession->peeraddr, sizeof(union capwap_addr));
rcu_read_unlock();
/* Remove session with address */
return sc_capwap_deleterunningsession(&peeraddr);
}
}
}
/* Search into setup session list */
list_for_each_entry_rcu(wtpsession, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Check setup session for delete: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
rcu_read_unlock();
/* Remove session with sessionid */
return sc_capwap_deletesetupsession(sessionid);
}
}
rcu_read_unlock();
TRACEKMOD("*** Session not found\n");
return -ENOENT;
}
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) {
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_getsession\n");
/* */
session = rcu_dereference_check(sc_wtpsession_hash[sc_capwap_hash(sockaddr)], lockdep_is_held(&sc_wtpsession_mutex));
while (session) {
if (!sc_addr_compare(sockaddr, &session->peeraddr)) {
break;
}
/* */
session = rcu_dereference_check(session->next, lockdep_is_held(&sc_wtpsession_mutex));
}
return session;
}
/* */
void sc_capwap_recvpacket(struct sk_buff* skb) {
uint32_t pos;
unsigned long flags;
TRACEKMOD("### sc_capwap_recvpacket\n");
spin_lock_irqsave(&sc_wtpsession_threads_lock, flags);
sc_wtpsession_threads_pos = ((sc_wtpsession_threads_pos + 1) % sc_wtpsession_threads_count);
pos = sc_wtpsession_threads_pos;
spin_unlock_irqrestore(&sc_wtpsession_threads_lock, flags);
TRACEKMOD("*** Add packet to thread: %u\n", pos);
/* Queue packet */
skb_queue_tail(&sc_wtpsession_threads[pos].queue, skb);
wake_up_interruptible(&sc_wtpsession_threads[pos].waitevent);
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
uint32_t hash;
struct sc_capwap_session* search;
struct sc_capwap_session* wtpsession = NULL;
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Receive unknown keep-alive: %s\n", sessionname);
} while(0);
#endif
/* Change read lock to update lock */
rcu_read_unlock();
mutex_lock(&sc_wtpsession_mutex);
/* Search and remove from setup session */
list_for_each_entry(search, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&search->sessionid, sessionname);
TRACEKMOD("*** Check setup session: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&search->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
wtpsession = search;
break;
}
}
/* */
if (wtpsession) {
TRACEKMOD("*** Setup session found\n");
list_del_rcu(&wtpsession->list);
synchronize_net();
} else {
TRACEKMOD("*** Setup session not found\n");
goto done;
}
/* */
hash = sc_capwap_hash(sockaddr);
memcpy(&wtpsession->peeraddr, sockaddr, sizeof(union capwap_addr));
/* Add to list */
list_add_rcu(&wtpsession->list, &sc_wtpsession_list);
wtpsession->next = sc_wtpsession_hash[hash];
rcu_assign_pointer(sc_wtpsession_hash[hash], wtpsession);
done:
rcu_read_lock();
mutex_unlock(&sc_wtpsession_mutex);
/* */
return wtpsession;
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) {
uint8_t* pos;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
struct sc_capwap_radio_addr* radioaddr = NULL;
int radioaddrsize = 0;
struct sc_capwap_wireless_information* winfo = NULL;
int winfosize = 0;
TRACEKMOD("### sc_capwap_parsingdatapacket\n");
/* Retrieve optional attribute */
pos = skb->data + sizeof(struct sc_capwap_header);
if (IS_FLAG_M_HEADER(header)) {
radioaddr = (struct sc_capwap_radio_addr*)pos;
radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3;
pos += radioaddrsize;
}
if (IS_FLAG_W_HEADER(header)) {
winfo = (struct sc_capwap_wireless_information*)pos;
radioaddrsize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3;
pos += winfosize;
}
/* TODO */
}
/* */
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingmgmtpacket\n");
/* Send packet with capwap header into userspace */
sc_netlink_notify_recv_data(&session->sessionid, skb->data, skb->len);
}

View File

@ -0,0 +1,26 @@
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
#define __KMOD_CAPWAP_PRIVATE_HEADER__
/* */
struct sc_capwap_workthread {
struct task_struct* thread;
struct sk_buff_head queue;
wait_queue_head_t waitevent;
};
/* */
int sc_capwap_init(uint32_t hash, uint32_t threads);
void sc_capwap_close(void);
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr);
/* */
int sc_capwap_sendkeepalive(const union capwap_addr* peeraddr);
/* */
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint16_t mtu);
int sc_capwap_deletesession(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

172
src/ac/kmod/capwap_rfc.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef __KMOD_CAPWAP_RFC_HEADER__
#define __KMOD_CAPWAP_RFC_HEADER__
#include <linux/types.h>
#include <asm/byteorder.h>
/* */
#define CAPWAP_RADIOID_MAX_COUNT 31
#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT))
#define CAPWAP_WLANID_MAX_COUNT 16
#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT))
/* */
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_ELEMENT_SESSIONID 35
/* */
#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \
sizeof(struct sc_capwap_header) + \
sizeof(struct sc_capwap_data_message) + \
sizeof(struct sc_capwap_message_element) + \
sizeof(struct sc_capwap_sessionid_element))
/* Preamble */
struct sc_capwap_preamble {
#if defined(__BIG_ENDIAN_BITFIELD)
uint8_t version: 4,
type: 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t type: 4,
version: 4;
#endif
} __packed;
/* DTLS header */
struct sc_capwap_dtls_header {
struct sc_capwap_preamble preamble;
uint8_t reserved[3];
} __packed;
/* Plain header */
struct sc_capwap_header {
struct sc_capwap_preamble preamble;
#if defined(__BIG_ENDIAN_BITFIELD)
uint16_t hlen: 5,
rid: 5,
wbid: 5,
flag_t: 1;
uint8_t flag_f: 1,
flag_l: 1,
flag_w: 1,
flag_m: 1,
flag_k: 1,
flag_res: 3;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint16_t _rid_hi: 3,
hlen: 5,
flag_t: 1,
wbid: 5,
_rid_lo: 2;
uint8_t flag_res: 3,
flag_k: 1,
flag_m: 1,
flag_w: 1,
flag_l: 1,
flag_f: 1;
#endif
__be16 frag_id;
__be16 frag_off;
} __packed;
/* Mac Address */
#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8
#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12
#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12
struct sc_capwap_radio_addr {
uint8_t length;
} __packed;
/* Wireless Information */
#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8
#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8
#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8
struct sc_capwap_wireless_information {
uint8_t length;
} __packed;
/* IEEE802.11 Wireless Information */
struct sc_capwap_ieee80211_frame_info {
uint8_t rssi;
uint8_t snr;
__be16 rate;
} __packed;
/* */
#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED)
/* Data channel message */
struct sc_capwap_data_message {
__be16 length;
} __packed;
/* Message element */
struct sc_capwap_message_element {
__be16 type;
__be16 length;
} __packed;
/* Session id message element */
struct sc_capwap_sessionid_element {
uint8_t id[16];
} __packed;
/* */
#define MACADDRESS_EUI48_LENGTH 6
struct sc_capwap_macaddress_eui48 {
uint8_t addr[MACADDRESS_EUI48_LENGTH];
} __packed;
/* */
#define MACADDRESS_EUI64_LENGTH 8
struct sc_capwap_macaddress_eui64 {
uint8_t addr[MACADDRESS_EUI64_LENGTH];
} __packed;
/* Capwap preamble */
#define CAPWAP_PROTOCOL_VERSION 0
#define CAPWAP_PREAMBLE_HEADER 0
#define CAPWAP_PREAMBLE_DTLS_HEADER 1
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element))
/* */
#define GET_VERSION_HEADER(x) ((x)->preamble.version)
#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y))
#define GET_TYPE_HEADER(x) ((x)->preamble.type)
#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y))
#define GET_HLEN_HEADER(x) ((x)->hlen)
#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y))
#if defined(__BIG_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((x)->rid))
#define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y))
#elif defined(__LITTLE_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo)))
#define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); })
#endif
#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid))
#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y))
#define IS_FLAG_T_HEADER(x) ((x)->flag_t)
#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0))
#define IS_FLAG_F_HEADER(x) ((x)->flag_f)
#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0))
#define IS_FLAG_L_HEADER(x) ((x)->flag_l)
#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0))
#define IS_FLAG_W_HEADER(x) ((x)->flag_w)
#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0))
#define IS_FLAG_M_HEADER(x) ((x)->flag_m)
#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0))
#define IS_FLAG_K_HEADER(x) ((x)->flag_k)
#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0))
#endif /* __KMOD_CAPWAP_RFC_HEADER__ */

13
src/ac/kmod/config.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __KMOD_CONFIG_HEADER__
#define __KMOD_CONFIG_HEADER__
#define DEBUGKMOD 1
#ifdef DEBUGKMOD
#define TRACEKMOD(s, args...) printk(s, ##args)
#else
#define TRACEKMOD(s, args...)
#endif
#endif /* __KMOD_CONFIG_HEADER__ */

View File

@ -1,21 +1,29 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include "netlinkapp.h"
/* */
static int __init smartcapwap_ac_init(void) {
int result = 0;
int ret;
/* */
result = nlsmartcapwap_ac_init();
TRACEKMOD("### smartcapwap_ac_init\n");
return result;
/* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
}
module_init(smartcapwap_ac_init);
/* */
static void __exit smartcapwap_ac_exit(void) {
nlsmartcapwap_ac_exit();
TRACEKMOD("### smartcapwap_ac_exit\n");
sc_netlink_exit();
}
module_exit(smartcapwap_ac_exit);

View File

@ -1,5 +1,8 @@
#include "config.h"
#include <linux/module.h>
#include <linux/version.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <net/genetlink.h>
@ -9,90 +12,251 @@
#include <linux/ieee80211.h>
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#include "capwap.h"
/* */
struct nlsmartcapwap_ac_device {
struct list_head list;
u32 usermodeid;
};
static u32 sc_netlink_usermodeid;
/* */
static u32 nlsmartcapwap_ac_usermodeid = 0;
static LIST_HEAD(nlsmartcapwap_ac_dev_list);
/* Netlink Family */
static struct genl_family nlsmartcapwap_ac_family = {
.id = GENL_ID_GENERATE,
.name = SMARTCAPWAP_AC_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_AC_ATTR_MAX,
.netnsok = true,
};
/* */
static void nlsmartcapwap_ac_free_device(struct nlsmartcapwap_ac_device* nldev) {
/* Free memory */
kfree(nldev);
}
/* */
static void nlsmartcapwap_ac_close(void) {
struct nlsmartcapwap_ac_device* nldev;
struct nlsmartcapwap_ac_device* tmp;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_ac_dev_list, list) {
list_del(&nldev->list);
/* Free device */
nlsmartcapwap_ac_free_device(nldev);
}
}
/* */
static int nlsmartcapwap_ac_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
u32 portid = info->snd_pid;
#else
u32 portid = info->snd_portid;
#endif
static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_pre_doit\n");
rtnl_lock();
return 0;
}
if (!nlsmartcapwap_ac_usermodeid) {
nlsmartcapwap_ac_usermodeid = portid;
} else if (nlsmartcapwap_ac_usermodeid == portid) {
ret = -EALREADY;
} else {
ret = -EBUSY;
}
/* */
static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_post_doit\n");
rtnl_unlock();
}
/* Netlink Family */
static struct genl_family sc_netlink_family = {
.id = GENL_ID_GENERATE,
.name = NLSMARTCAPWAP_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_ATTR_MAX,
.netnsok = true,
.pre_doit = sc_netlink_pre_doit,
.post_doit = sc_netlink_post_doit,
};
/* */
static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) {
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_bind\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(&sockaddr);
}
/* */
static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) {
int ret;
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_send_keepalive\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) {
return -EINVAL;
}
/* */
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Send keep-alive packet */
ret = sc_capwap_sendkeepalive(&sockaddr);
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) {
int length;
struct sk_buff* skbdata;
union capwap_addr sockaddr;
struct sc_skb_capwap_cb* cb;
TRACEKMOD("### sc_netlink_send_data\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
} else if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
return -EINVAL;
}
/* */
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Create socket buffer */
length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]);
skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL);
if (!skbdata) {
return -ENOMEM;
}
/* Reserve space for Capwap Header */
skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH);
/* Copy data into socket buffer */
memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length);
/* */
cb = CAPWAP_SKB_CB(skbdata);
cb->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE | SKB_CAPWAP_FLAG_PEERADDRESS | SKB_CAPWAP_FLAG_RADIOID | SKB_CAPWAP_FLAG_BINDING;
sc_addr_tolittle(&sockaddr, &cb->peeraddr);
cb->radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
cb->binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]);
/* */
sc_capwap_recvpacket(skbdata);
return 0;
}
/* */
static int sc_netlink_new_session(struct sk_buff* skb, struct genl_info* info) {
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_new_session\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session ID */
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element))) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) {
return -EINVAL;
}
}
/* New session */
return sc_capwap_newsession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), mtu);
}
/* */
static int sc_netlink_delete_session(struct sk_buff* skb, struct genl_info* info) {
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_delete_session\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session ID */
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element))) {
return -EINVAL;
}
/* Check Address */
if (info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) == sizeof(struct sockaddr_storage))) {
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
} else {
sockaddr.ss.ss_family = AF_UNSPEC;
}
/* Delete session */
return sc_capwap_deletesession(((sockaddr.ss.ss_family == AF_UNSPEC) ? NULL : &sockaddr), (struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]));
}
/* */
static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
TRACEKMOD("### sc_netlink_link\n");
if (!info->attrs[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD] || !info->attrs[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT]) {
TRACEKMOD("*** Invalid link argument\n");
return -EINVAL;
}
if (!sc_netlink_usermodeid) {
uint32_t hash = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD]);
uint32_t threads = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT]);
if (!hash || !threads) {
TRACEKMOD("*** Invalid link argument: %u %u\n", hash, threads);
return -EINVAL;
}
/* Initialize library */
ret = sc_capwap_init(hash, threads);
if (!ret) {
sc_netlink_usermodeid = info->snd_portid;
/* Deny unload module */
try_module_get(THIS_MODULE);
}
} else if (sc_netlink_usermodeid == info->snd_portid) {
TRACEKMOD("*** Already link\n");
ret = -EALREADY;
} else {
TRACEKMOD("*** Busy kernel link\n");
ret = -EBUSY;
}
return ret;
}
/* */
static int nlsmartcapwap_ac_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
struct netlink_notify* notify = (struct netlink_notify*)_notify;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
u32 portid = notify->pid;
#else
u32 portid = notify->portid;
#endif
/* */
if (state == NETLINK_URELEASE) {
rtnl_lock();
if (nlsmartcapwap_ac_usermodeid == portid) {
nlsmartcapwap_ac_usermodeid = 0;
if (sc_netlink_usermodeid == notify->portid) {
/* Close capwap engine */
sc_capwap_close();
/* Close all devices */
nlsmartcapwap_ac_close();
/* Allow unload module */
module_put(THIS_MODULE);
sc_netlink_usermodeid = 0;
}
rtnl_unlock();
@ -102,57 +266,172 @@ static int nlsmartcapwap_ac_netlink_notify(struct notifier_block* nb, unsigned l
}
/* */
static const struct nla_policy nlsmartcapwap_ac_policy[NLSMARTCAPWAP_AC_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_AC_ATTR_FLAGS] = { .type = NLA_U32 },
static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN + CAPWAP_HEADER_MAX_LENGTH },
[NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT] = { .type = NLA_U32 },
};
/* Netlink Ops */
static struct genl_ops nlsmartcapwap_ac_ops[] = {
static struct genl_ops sc_netlink_ops[] = {
{
.cmd = NLSMARTCAPWAP_AC_CMD_LINK,
.doit = nlsmartcapwap_ac_link,
.policy = nlsmartcapwap_ac_policy,
.cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = sc_netlink_link,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_BIND,
.doit = sc_netlink_bind,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
.doit = sc_netlink_send_keepalive,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_DATA,
.doit = sc_netlink_send_data,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_NEW_SESSION,
.doit = sc_netlink_new_session,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_DELETE_SESSION,
.doit = sc_netlink_delete_session,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
};
/* Netlink notify */
static struct notifier_block nlsmartcapwap_ac_netlink_notifier = {
.notifier_call = nlsmartcapwap_ac_netlink_notify,
static struct notifier_block sc_netlink_notifier = {
.notifier_call = sc_netlink_notify,
};
/* */
int nlsmartcapwap_ac_init(void) {
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_keepalive\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr->ss) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_data\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_init(void) {
int ret;
TRACEKMOD("### sc_netlink_init\n");
/* */
sc_netlink_usermodeid = 0;
/* Register netlink family */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops, sizeof(nlsmartcapwap_ac_ops) / sizeof(nlsmartcapwap_ac_ops[0]));
ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops, sizeof(sc_netlink_ops) / sizeof(sc_netlink_ops[0]));
#else
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops);
ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops);
#endif
if (ret) {
return ret;
goto error;
}
/* Register netlink notifier */
ret = netlink_register_notifier(&nlsmartcapwap_ac_netlink_notifier);
ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) {
genl_unregister_family(&nlsmartcapwap_ac_family);
return ret;
goto error2;
}
return 0;
error2:
genl_unregister_family(&sc_netlink_family);
error:
return ret;
}
/* */
void nlsmartcapwap_ac_exit(void) {
/* */
rtnl_lock();
nlsmartcapwap_ac_close();
rtnl_unlock();
void sc_netlink_exit(void) {
TRACEKMOD("### sc_netlink_exit\n");
/* */
netlink_unregister_notifier(&nlsmartcapwap_ac_netlink_notifier);
genl_unregister_family(&nlsmartcapwap_ac_family);
netlink_unregister_notifier(&sc_netlink_notifier);
genl_unregister_family(&sc_netlink_family);
}

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_AC_NETLINKAPP_HEADER__
#define __KMOD_AC_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
int nlsmartcapwap_ac_init(void);
void nlsmartcapwap_ac_exit(void);
int sc_netlink_init(void);
void sc_netlink_exit(void);
/* */
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length);
#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */

View File

@ -2,28 +2,55 @@
#define __AC_NLSMARTCAPWAP_HEADER__
/* */
#define SMARTCAPWAP_AC_GENL_NAME "smartcapwap_ac"
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac"
/* */
enum nlsmartcapwap_ac_attrs {
NLSMARTCAPWAP_AC_ATTR_UNSPEC,
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
NLSMARTCAPWAP_AC_ATTR_FLAGS,
/* */
enum sc_netlink_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_FLAGS,
NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_RADIOID,
NLSMARTCAPWAP_ATTR_BINDING,
NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD,
NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT,
/* Last attribute */
__NLSMARTCAPWAP_AC_ATTR_AFTER_LAST,
NLSMARTCAPWAP_AC_ATTR_MAX = __NLSMARTCAPWAP_AC_ATTR_AFTER_LAST - 1
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
};
/* */
enum nlsmartcapwap_ac_commands {
NLSMARTCAPWAP_AC_CMD_UNSPEC,
enum sc_netlink_commands {
NLSMARTCAPWAP_CMD_UNSPEC,
NLSMARTCAPWAP_AC_CMD_LINK,
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_NEW_SESSION,
NLSMARTCAPWAP_CMD_DELETE_SESSION,
NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
/* Last command */
__NLSMARTCAPWAP_AC_CMD_AFTER_LAST,
NLSMARTCAPWAP_AC_CMD_MAX = __NLSMARTCAPWAP_AC_CMD_AFTER_LAST - 1
__NLSMARTCAPWAP_CMD_AFTER_LAST,
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
};
#endif /* __AC_NLSMARTCAPWAP_HEADER__ */

257
src/ac/kmod/socket.c Normal file
View File

@ -0,0 +1,257 @@
#include "config.h"
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/kthread.h>
#include <linux/net.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <net/ipv6.h>
#include <net/sock.h>
#include <net/udp.h>
#include "socket.h"
#include "capwap.h"
/* Socket */
#define SOCKET_COUNT 2
static struct socket* sc_sockets[SOCKET_COUNT];
/* */
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_socket_recvpacket\n");
/* */
cb->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
/* */
sc_capwap_recvpacket(skb);
return 0;
}
/* */
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
int ret;
TRACEKMOD("### sc_socket_create\n");
/* Create socket */
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
if (ret) {
goto failure;
}
/* Bind to interface */
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
if (ret) {
goto failure2;
}
/* Set callback */
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
/* */
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
union capwap_addr localaddr;
int localaddrsize = sizeof(union capwap_addr);
/* Retrieve port */
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
if (ret) {
goto failure2;
}
/* */
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
sockaddr->sin.sin_port = localaddr.sin.sin_port;
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
} else {
ret = -EFAULT;
goto failure2;
}
}
return ret;
failure2:
sock_release(sc_sockets[type]);
sc_sockets[type] = 0;
failure:
return ret;
}
/* */
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
unsigned char* nethdr;
TRACEKMOD("### sc_socket_getpeeraddr\n");
/* */
nethdr = skb_network_header(skb);
if (!nethdr) {
return -EINVAL;
}
/* */
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {
/* Validate IPv4 header */
if ((nethdr[0] & 0xf0) != 0x40) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin.sin_family = AF_INET;
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
peeraddr->sin.sin_port = udp_hdr(skb)->source;
break;
}
case ETH_P_IPV6: {
/* Validate IPv6 header */
if ((nethdr[0] & 0xf0) != 0x60) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin6.sin6_family = AF_INET6;
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
break;
}
default: {
return -EINVAL;
}
}
return 0;
}
/* */
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
struct kvec vec;
struct msghdr msg;
TRACEKMOD("### sc_socket_send\n");
/* */
vec.iov_base = buffer;
vec.iov_len = length;
/* */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = sockaddr;
msg.msg_namelen = sizeof(union capwap_addr);
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
/* */
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
}
/* */
int sc_socket_init(void) {
TRACEKMOD("### sc_socket_init\n");
memset(sc_sockets, 0, sizeof(sc_sockets));
return 0;
}
/* */
int sc_socket_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_socket_bind\n");
/* */
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
return -EBUSY;
}
/* UDP socket */
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
if (ret) {
goto failure;
}
/* UDPLite socket */
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
if (ret) {
goto failure;
}
/* */
udp_encap_enable();
if (sockaddr->ss.ss_family == AF_INET6) {
udpv6_encap_enable();
}
return 0;
failure:
sc_socket_close();
return ret;
}
/* */
void sc_socket_close(void) {
TRACEKMOD("### sc_socket_close\n");
/* Close sockets */
if (sc_sockets[SOCKET_UDP]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDP]);
}
if (sc_sockets[SOCKET_UDPLITE]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDPLITE]);
}
memset(sc_sockets, 0, sizeof(sc_sockets));
}
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
TRACEKMOD("### sc_addr_compare\n");
if (addr1->ss.ss_family == addr2->ss.ss_family) {
if (addr1->ss.ss_family == AF_INET) {
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
} else if (addr1->ss.ss_family == AF_INET6) {
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
}
}
return -1;
}
/* */
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little) {
little->family = (uint8_t)addr->ss.ss_family;
if (addr->ss.ss_family == AF_INET) {
memcpy(&little->addr4, &addr->sin.sin_addr, sizeof(struct in_addr));
little->port = addr->sin.sin_port;
} else if (addr->ss.ss_family == AF_INET6) {
memcpy(&little->addr6, &addr->sin6.sin6_addr, sizeof(struct in6_addr));
little->port = addr->sin6.sin6_port;
}
}
/* */
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr) {
memset(addr, 0, sizeof(union capwap_addr));
addr->ss.ss_family = little->family;
if (little->family == AF_INET) {
memcpy(&addr->sin.sin_addr, &little->addr4, sizeof(struct in_addr));
addr->sin.sin_port = little->port;
} else if (little->family == AF_INET6) {
memcpy(&addr->sin6.sin6_addr, &little->addr6, sizeof(struct in6_addr));
addr->sin6.sin6_port = little->port;
}
}

45
src/ac/kmod/socket.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __KMOD_SOCKET_HEADER__
#define __KMOD_SOCKET_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
/* */
#define SOCKET_UDP 0
#define SOCKET_UDPLITE 1
/* Little socket address */
struct capwap_addr_little {
uint8_t family;
union {
struct in_addr addr4;
struct in6_addr addr6;
};
uint16_t port;
};
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
/* */
int sc_socket_init(void);
void sc_socket_close(void);
/* */
int sc_socket_bind(union capwap_addr* sockaddr);
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little);
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr);
#endif /* __KMOD_SOCKET_HEADER__ */