The capwap data channel migrated from userspace to kernalspace
This commit is contained in:
78
src/ac/ac.c
78
src/ac/ac.c
@ -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 */
|
||||
|
11
src/ac/ac.h
11
src/ac/ac.h
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)) {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(¬ify, 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*)¬ify, 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(¬ify, 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*)¬ify, 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 {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
210
src/ac/ac_kmod.c
210
src/ac/ac_kmod.c
@ -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;
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -21,7 +21,7 @@
|
||||
/* */
|
||||
struct ac_http_soap_server {
|
||||
int protocol;
|
||||
struct sockaddr_storage address;
|
||||
union sockaddr_capwap address;
|
||||
|
||||
char* host;
|
||||
char* path;
|
||||
|
@ -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(¬ify, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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
621
src/ac/kmod/capwap.c
Normal 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
128
src/ac/kmod/capwap.h
Normal 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__ */
|
636
src/ac/kmod/capwap_private.c
Normal file
636
src/ac/kmod/capwap_private.c
Normal 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);
|
||||
}
|
26
src/ac/kmod/capwap_private.h
Normal file
26
src/ac/kmod/capwap_private.h
Normal 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
172
src/ac/kmod/capwap_rfc.h
Normal 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
13
src/ac/kmod/config.h
Normal 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__ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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
257
src/ac/kmod/socket.c
Normal 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
45
src/ac/kmod/socket.h
Normal 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__ */
|
Reference in New Issue
Block a user