diff --git a/src/ac/ac.c b/src/ac/ac.c index 896d889..b6df933 100644 --- a/src/ac/ac.c +++ b/src/ac/ac.c @@ -3,6 +3,7 @@ #include "ac_session.h" #include "capwap_dtls.h" #include "capwap_socket.h" +#include "ac_wlans.h" #include @@ -12,20 +13,61 @@ struct ac_t g_ac; +/* */ #define AC_STANDARD_NAME "Unknown AC" +#define AC_STATIONS_HASH_SIZE 65536 +#define AC_IFDATACHANNEL_HASH_SIZE 16 /* Local param */ static char g_configurationfile[260] = AC_DEFAULT_CONFIGURATION_FILE; /* */ -static unsigned long ac_stations_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { +static unsigned long ac_stations_item_gethash(const void* key, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; - ASSERT(keysize == MACADDRESS_EUI48_LENGTH); - return ((((unsigned long)macaddress[4] << 8) | (unsigned long)macaddress[5]) ^ ((unsigned long)macaddress[3] << 4)); } +/* */ +static const void* ac_stations_item_getkey(const void* data) { + return (const void*)((struct ac_station*)data)->address; +} + +/* */ +static int ac_stations_item_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + +/* */ +static unsigned long ac_ifdatachannel_item_gethash(const void* key, unsigned long hashsize) { + return ((*(unsigned long*)key) % AC_IFDATACHANNEL_HASH_SIZE); +} + +/* */ +static const void* ac_ifdatachannel_item_getkey(const void* data) { + return (const void*)&((struct ac_if_datachannel*)data)->index; +} + +/* */ +static int ac_ifdatachannel_item_cmp(const void* key1, const void* key2) { + unsigned long value1 = *(unsigned long*)key1; + unsigned long value2 = *(unsigned long*)key2; + + return ((value1 == value2) ? 0 : ((value1 < value2) ? -1 : 1)); +} + +/* */ +static void ac_ifdatachannel_item_free(void* data) { + struct ac_if_datachannel* datachannel = (struct ac_if_datachannel*)data; + + /* */ + if (datachannel->ifindex >= 0) { + ac_kmod_delete_iface(datachannel->ifindex); + } + + capwap_free(data); +} + /* Alloc AC */ static int ac_init(void) { g_ac.standalone = 1; @@ -73,13 +115,25 @@ static int ac_init(void) { /* Sessions */ g_ac.sessions = capwap_list_create(); - g_ac.sessionsdata = capwap_list_create(); g_ac.sessionsthread = capwap_list_create(); capwap_rwlock_init(&g_ac.sessionslock); /* Stations */ - g_ac.stations = capwap_hash_create(AC_STATIONS_HASH_SIZE, AC_STATIONS_KEY_SIZE, ac_stations_item_gethash, NULL, NULL); - capwap_rwlock_init(&g_ac.stationslock); + g_ac.authstations = capwap_hash_create(AC_STATIONS_HASH_SIZE); + g_ac.authstations->item_gethash = ac_stations_item_gethash; + g_ac.authstations->item_getkey = ac_stations_item_getkey; + g_ac.authstations->item_cmp = ac_stations_item_cmp; + + capwap_rwlock_init(&g_ac.authstationslock); + + /* Data Channel Interfaces */ + g_ac.ifdatachannel = capwap_hash_create(AC_IFDATACHANNEL_HASH_SIZE); + g_ac.ifdatachannel->item_gethash = ac_ifdatachannel_item_gethash; + g_ac.ifdatachannel->item_getkey = ac_ifdatachannel_item_getkey; + g_ac.ifdatachannel->item_cmp = ac_ifdatachannel_item_cmp; + g_ac.ifdatachannel->item_free = ac_ifdatachannel_item_free; + + capwap_rwlock_init(&g_ac.ifdatachannellock); /* Backend */ g_ac.availablebackends = capwap_array_create(sizeof(struct ac_http_soap_server*), 0, 0); @@ -114,15 +168,19 @@ static void ac_destroy(void) { /* Sessions */ capwap_list_free(g_ac.sessions); - capwap_list_free(g_ac.sessionsdata); capwap_list_free(g_ac.sessionsthread); capwap_rwlock_destroy(&g_ac.sessionslock); ac_msgqueue_free(); + /* Data Channel Interfaces */ + ASSERT(g_ac.ifdatachannel->count == 0); + capwap_hash_free(g_ac.ifdatachannel); + capwap_rwlock_destroy(&g_ac.ifdatachannellock); + /* Stations */ - ASSERT(g_ac.stations->count == 0); - capwap_hash_free(g_ac.stations); - capwap_rwlock_destroy(&g_ac.stationslock); + ASSERT(g_ac.authstations->count == 0); + capwap_hash_free(g_ac.authstations); + capwap_rwlock_destroy(&g_ac.authstationslock); /* Backend */ if (g_ac.backendacid) { @@ -801,7 +859,7 @@ int main(int argc, char** argv) { result = ac_configure(); if (result == CAPWAP_SUCCESSFUL) { /* Connect AC to kernel module */ - if (!ac_kmod_init(16, 4)) { + if (!ac_kmod_init(16, 4)) { /* TODO change static value with param */ /* 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"); diff --git a/src/ac/ac.h b/src/ac/ac.h index 1bfd46c..6060ac9 100644 --- a/src/ac/ac.h +++ b/src/ac/ac.h @@ -14,6 +14,7 @@ #include #include +#include #include @@ -57,10 +58,6 @@ #define AC_IDLE_TIMEOUT_INTERVAL 300000 #define AC_WTP_FALLBACK_MODE CAPWAP_WTP_FALLBACK_ENABLED -/* */ -#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; \ @@ -68,6 +65,18 @@ (error ? result : NULL); \ }) +/* */ +struct ac_if_datachannel { + unsigned long index; + + int ifindex; + char ifname[IFNAMSIZ]; + + int mtu; + + char bridge[IFNAMSIZ]; +}; + /* */ struct ac_state { struct capwap_ecnsupport_element ecn; @@ -121,13 +130,16 @@ struct ac_t { /* Sessions */ struct capwap_list* sessions; - struct capwap_list* sessionsdata; struct capwap_list* sessionsthread; capwap_rwlock_t sessionslock; - /* Stations */ - struct capwap_hash* stations; - capwap_rwlock_t stationslock; + /* Authorative Stations */ + struct capwap_hash* authstations; + capwap_rwlock_t authstationslock; + + /* Data Channel Interfaces */ + struct capwap_hash* ifdatachannel; + capwap_rwlock_t ifdatachannellock; /* Dtls */ int enabledtls; @@ -145,7 +157,9 @@ struct ac_session_thread_t { }; /* AC session message queue item */ -#define AC_MESSAGE_QUEUE_CLOSE_THREAD 1 +#define AC_MESSAGE_QUEUE_CLOSE_THREAD 1 +#define AC_MESSAGE_QUEUE_CLOSE_ALLSESSIONS 2 +#define AC_MESSAGE_QUEUE_UPDATE_CONFIGURATION 3 struct ac_session_msgqueue_item_t { unsigned long message; @@ -154,6 +168,10 @@ struct ac_session_msgqueue_item_t { struct { pthread_t threadid; } message_close_thread; + + struct { + struct json_object* jsonroot; + } message_configuration; }; }; diff --git a/src/ac/ac_backend.c b/src/ac/ac_backend.c index 20427a7..d30c99d 100644 --- a/src/ac/ac_backend.c +++ b/src/ac/ac_backend.c @@ -3,7 +3,6 @@ #include "ac_backend.h" #include "ac_soap.h" #include "ac_session.h" -#include /* */ #define AC_BACKEND_WAIT_TIMEOUT 10000 @@ -32,9 +31,14 @@ struct ac_backend_t { static struct ac_backend_t g_ac_backend; +/* */ +static struct ac_http_soap_server* ac_backend_get_server(void) { + return *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); +} + /* */ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct json_object* jsonparams) { - int result = 0; + int result = -1; struct ac_session_t* session; struct json_object* jsonwtpid; @@ -47,7 +51,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct /* WTPId */ jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return 0; + return -1; } /* Get session */ @@ -67,7 +71,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct /* */ ac_session_release_reference(session); - result = 1; + result = 0; } return result; @@ -75,7 +79,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct /* */ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_object* jsonparams) { - int result = 0; + int result = -1; struct ac_session_t* session; struct json_object* jsonwtpid; struct json_object* jsonimage; @@ -95,19 +99,19 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob /* WTPId */ jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return 0; + return -1; } /* ImageIdentifier */ jsonimage = compat_json_object_object_get(jsonparams, "ImageIdentifier"); if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) { - return 0; + return -1; } 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; + return -1; } /* Get session */ @@ -136,7 +140,7 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob /* Notify Action */ capwap_logging_debug("Receive reset request for WTP %s", session->wtpid); ac_session_send_action(session, AC_SESSION_ACTION_RESET_WTP, 0, (void*)reset, length); - result = 1; + result = 0; /* */ capwap_free(reset); @@ -150,7 +154,7 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob /* */ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_object* jsonparams) { - int result = 0; + int result = -1; struct ac_session_t* session; struct json_object* jsonwtpid; struct json_object* jsonradioid; @@ -166,9 +170,9 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj /* Params AddWLAN Action { - WTPId: [string], - RadioId: [int], - VirtualAPId: [int], + WTPID: [string], + RadioID: [int], + WLANID: [int], Capability: [int], Key: { TODO @@ -185,28 +189,28 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj } */ - /* WTPId */ - jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); + /* WTPID */ + jsonwtpid = compat_json_object_object_get(jsonparams, "WTPID"); if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return 0; + return -1; } - /* RadioId */ - jsonradioid = compat_json_object_object_get(jsonparams, "RadioId"); + /* RadioID */ + jsonradioid = compat_json_object_object_get(jsonparams, "RadioID"); if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) { - return 0; + return -1; } - /* VirtualAPId */ - jsonwlanid = compat_json_object_object_get(jsonparams, "VirtualAPId"); + /* WLANID */ + jsonwlanid = compat_json_object_object_get(jsonparams, "WLANID"); if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) { - return 0; + return -1; } /* Capability */ jsoncapability = compat_json_object_object_get(jsonparams, "Capability"); if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) { - return 0; + return -1; } /* Key */ @@ -215,31 +219,31 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj /* DefaultQoS */ jsonqos = compat_json_object_object_get(jsonparams, "DefaultQoS"); if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) { - return 0; + return -1; } /* AuthType */ jsonauthtype = compat_json_object_object_get(jsonparams, "AuthType"); if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) { - return 0; + return -1; } /* MACMode */ jsonmacmode = compat_json_object_object_get(jsonparams, "MACMode"); if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) { - return 0; + return -1; } /* TunnelMode */ jsontunnelmode = compat_json_object_object_get(jsonparams, "TunnelMode"); if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) { - return 0; + return -1; } /* SuppressSSID */ jsonhidessid = compat_json_object_object_get(jsonparams, "SuppressSSID"); if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) { - return 0; + return -1; } /* SSID */ @@ -247,10 +251,10 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) { ssid = json_object_get_string(jsonssid); if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) { - return 0; + return -1; } } else { - return 0; + return -1; } /* IE */ @@ -291,7 +295,7 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj /* */ ac_session_release_reference(session); capwap_free(addwlan); - result = 1; + result = 0; } return result; @@ -299,14 +303,14 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj /* */ static int ac_backend_parsing_updatewlan_event(const char* idevent, struct json_object* jsonparams) { - int result = 0; + int result = -1; return result; } /* */ static int ac_backend_parsing_deletewlan_event(const char* idevent, struct json_object* jsonparams) { - int result = 0; + int result = -1; return result; } @@ -322,7 +326,7 @@ static int ac_backend_soap_update_event(const char* idevent, int status) { ASSERT(g_ac_backend.backendsessionid != NULL); /* Get HTTP Soap Server */ - server = *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); + server = ac_backend_get_server(); /* Critical section */ capwap_lock_enter(&g_ac_backend.lock); @@ -370,7 +374,150 @@ static int ac_backend_soap_update_event(const char* idevent, int status) { } /* */ -static void ac_backend_parsing_event(struct json_object* jsonitem) { +static int ac_backend_soap_getconfiguration(void) { + int result = -1; + struct ac_soap_request* request; + struct ac_http_soap_server* server; + struct json_object* jsonroot = NULL; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid != NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("getConfiguration", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return -1; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + /* Get Configuration result */ + jsonroot = ac_soapclient_parse_json_response(response); + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + /* Send JSON command to primary thread */ + if (jsonroot) { + result = ac_msgqueue_update_configuration(jsonroot); + if (result) { + json_object_put(jsonroot); + } + } + + return result; +} + +/* */ +static int ac_backend_soap_join(int forcereset) { + struct ac_soap_request* request; + struct ac_http_soap_server* server; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid == NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("joinBackend", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idac", g_ac.backendacid); + ac_soapclient_add_param(request, "xs:string", "version", g_ac.backendversion); + ac_soapclient_add_param(request, "xs:boolean", "forcereset", (forcereset ? "true" : "false")); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return -1; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + /* Get join result */ + if ((response->responsecode == HTTP_RESULT_OK) && response->xmlResponseReturn) { + xmlChar* xmlResult = xmlNodeGetContent(response->xmlResponseReturn); + if (xmlStrlen(xmlResult)) { + g_ac_backend.backendsessionid = capwap_duplicate_string((const char*)xmlResult); + } + + xmlFree(xmlResult); + } + + /* */ + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + /* Retrieve AC configuration */ + if (g_ac_backend.backendsessionid && forcereset) { + if (ac_backend_soap_getconfiguration()) { + capwap_logging_error("Unable to get AC configuration from Backend Server"); + capwap_free(g_ac_backend.backendsessionid); + g_ac_backend.backendsessionid = NULL; + } + } + + return (g_ac_backend.backendsessionid ? 0 : -1); +} + +/* */ +static int ac_backend_parsing_event(struct json_object* jsonitem) { + int result = -1; struct json_object* jsonvalue; ASSERT(jsonitem != NULL); @@ -397,8 +544,6 @@ static void ac_backend_parsing_event(struct json_object* jsonitem) { if (action) { jsonvalue = compat_json_object_object_get(jsonitem, "Params"); if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { - int result = 0; - /* Parsing params according to the action */ if (!strcmp(action, "CloseWTPSession")) { result = ac_backend_parsing_closewtpsession_event(idevent, jsonvalue); @@ -413,78 +558,11 @@ static void ac_backend_parsing_event(struct json_object* jsonitem) { } /* Notify result action */ - ac_backend_soap_update_event(idevent, (result ? SOAP_EVENT_STATUS_RUNNING : SOAP_EVENT_STATUS_GENERIC_ERROR)); + ac_backend_soap_update_event(idevent, (!result ? SOAP_EVENT_STATUS_RUNNING : SOAP_EVENT_STATUS_GENERIC_ERROR)); } } } } -} - -/* */ -static int ac_backend_soap_join(int forcereset) { - int result = 0; - struct ac_soap_request* request; - struct ac_http_soap_server* server; - - ASSERT(g_ac_backend.soaprequest == NULL); - ASSERT(g_ac_backend.backendsessionid == NULL); - - /* Get HTTP Soap Server */ - server = *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - if (!g_ac_backend.endthread) { - request = ac_soapclient_create_request("joinBackend", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idac", g_ac.backendacid); - ac_soapclient_add_param(request, "xs:string", "version", g_ac.backendversion); - ac_soapclient_add_param(request, "xs:boolean", "forcereset", (forcereset ? "true" : "false")); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - } - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return 0; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - /* Get join result */ - if ((response->responsecode == HTTP_RESULT_OK) && response->xmlResponseReturn) { - xmlChar* xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (xmlStrlen(xmlResult)) { - result = 1; - g_ac_backend.backendsessionid = capwap_duplicate_string((const char*)xmlResult); - } - - xmlFree(xmlResult); - } - - /* */ - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); return result; } @@ -500,7 +578,7 @@ static int ac_backend_soap_waitevent(void) { ASSERT(g_ac_backend.backendsessionid != NULL); /* Get HTTP Soap Server */ - server = *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); + server = ac_backend_get_server(); /* Critical section */ capwap_lock_enter(&g_ac_backend.lock); @@ -533,34 +611,7 @@ static int ac_backend_soap_waitevent(void) { struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); if (response) { /* Wait event result */ - if ((response->responsecode == HTTP_RESULT_OK) && response->xmlResponseReturn) { - int length; - char* json; - xmlChar* xmlResult; - - /* Decode base64 result */ - xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (!xmlResult) { - return CAPWAP_RESULTCODE_FAILURE; - } - - length = xmlStrlen(xmlResult); - if (!length) { - xmlFree(xmlResult); - return CAPWAP_RESULTCODE_FAILURE; - } - - json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); - ac_base64_string_decode((const char*)xmlResult, json); - - xmlFree(xmlResult); - - /* Parsing JSON result */ - jsonroot = json_tokener_parse(json); - capwap_free(json); - } - - /* */ + jsonroot = ac_soapclient_parse_json_response(response); ac_soapclient_free_response(response); } } @@ -582,15 +633,19 @@ static int ac_backend_soap_waitevent(void) { /* Parsing every message into JSON result */ length = json_object_array_length(jsonroot); - for (i = 0; i < length; i++) { - struct json_object* jsonitem = json_object_array_get_idx(jsonroot, i); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_object)) { - ac_backend_parsing_event(jsonitem); + if (!length) { + result = 0; + } else { + for (i = 0; i < length; i++) { + struct json_object* jsonitem = json_object_array_get_idx(jsonroot, i); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_object)) { + result = ac_backend_parsing_event(jsonitem); + if (result) { + break; + } + } } } - - /* Parsing complete */ - result = 0; } /* Free JSON */ @@ -613,7 +668,7 @@ static void ac_backend_soap_leave(void) { } /* Get HTTP Soap Server */ - server = *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); + server = ac_backend_get_server(); /* Critical section */ capwap_lock_enter(&g_ac_backend.lock); @@ -656,7 +711,6 @@ static void ac_backend_soap_leave(void) { /* */ static void ac_backend_run(void) { - int result; int connected = 0; int forcereset = 1; @@ -664,8 +718,7 @@ static void ac_backend_run(void) { while (!g_ac_backend.endthread) { if (connected) { - result = ac_backend_soap_waitevent(); - if (result < 0) { + if (ac_backend_soap_waitevent()) { if (g_ac_backend.endthread) { break; } @@ -684,7 +737,7 @@ static void ac_backend_run(void) { } } else { /* Join with a Backend Server */ - if (ac_backend_soap_join(forcereset)) { + if (!ac_backend_soap_join(forcereset)) { capwap_logging_debug("Joined with Backend Server"); /* Join Complete */ @@ -707,9 +760,14 @@ static void ac_backend_run(void) { g_ac_backend.backendstatus = 0; g_ac_backend.errorjoinbackend = 0; - /* Wait before retry join to backend server */ capwap_lock_exit(&g_ac_backend.backendlock); + + /* Close all sessions */ + ac_msgqueue_close_allsessions(); + + /* Wait before retry join to backend server */ capwap_event_wait_timeout(&g_ac_backend.wait, AC_BACKEND_WAIT_TIMEOUT); + capwap_lock_enter(&g_ac_backend.backendlock); } } @@ -758,7 +816,7 @@ struct ac_http_soap_request* ac_backend_createrequest_with_session(char* method, capwap_lock_enter(&g_ac_backend.backendlock); if (ac_backend_isconnect()) { - server = *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); + server = ac_backend_get_server(); /* Build Soap Request */ request = ac_soapclient_create_request(method, SOAP_NAMESPACE_URI); diff --git a/src/ac/ac_dfa_configure.c b/src/ac/ac_dfa_configure.c index 18fda89..95e7316 100644 --- a/src/ac/ac_dfa_configure.c +++ b/src/ac/ac_dfa_configure.c @@ -259,9 +259,7 @@ static struct ac_soap_response* ac_dfa_state_configure_parsing_request(struct ac /* */ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct ac_soap_response* response, struct capwap_packet_txmng* txmngpacket) { int length; - char* json; unsigned long i; - xmlChar* xmlResult; struct json_object* jsonroot; struct json_object* jsonelement; struct capwap_array* radioadmstate; @@ -270,10 +268,6 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess struct capwap_wtpfallback_element responsewtpfallback; unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header); - if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { - return CAPWAP_RESULTCODE_FAILURE; - } - /* Receive SOAP response with JSON result { CAPWAPTimers: { @@ -399,27 +393,11 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess } */ - /* Decode base64 result */ - xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (!xmlResult) { - return CAPWAP_RESULTCODE_FAILURE; - } - - length = xmlStrlen(xmlResult); - if (!length) { - return CAPWAP_RESULTCODE_FAILURE; - } - - json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); - ac_base64_string_decode((const char*)xmlResult, json); - - xmlFree(xmlResult); - - /* Parsing JSON result */ - jsonroot = json_tokener_parse(json); - capwap_free(json); - /* Add message elements response, every local value can be overwrite from backend server */ + jsonroot = ac_soapclient_parse_json_response(response); + if (!jsonroot) { + return CAPWAP_RESULTCODE_FAILURE; + } /* CAPWAP Timers */ memcpy(&responsetimers, &session->dfa.timers, sizeof(struct capwap_timers_element)); diff --git a/src/ac/ac_dfa_datacheck.c b/src/ac/ac_dfa_datacheck.c index de3b220..3087c3f 100644 --- a/src/ac/ac_dfa_datacheck.c +++ b/src/ac/ac_dfa_datacheck.c @@ -127,41 +127,18 @@ static struct ac_soap_response* ac_dfa_state_datacheck_parsing_request(struct ac /* */ static uint32_t ac_dfa_state_datacheck_create_response(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct ac_soap_response* response, struct capwap_packet_txmng* txmngpacket) { - int length; - char* json; - xmlChar* xmlResult; struct json_object* jsonroot; - if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { - return CAPWAP_RESULTCODE_FAILURE; - } - /* Receive SOAP response with JSON result { } */ - /* Decode base64 result */ - xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (!xmlResult) { - return CAPWAP_RESULTCODE_FAILURE; - } - - length = xmlStrlen(xmlResult); - if (!length) { - return CAPWAP_RESULTCODE_FAILURE; - } - - json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); - ac_base64_string_decode((const char*)xmlResult, json); - - xmlFree(xmlResult); - - /* Parsing JSON result */ - jsonroot = json_tokener_parse(json); - capwap_free(json); - /* Add message elements response, every local value can be overwrite from backend server */ + jsonroot = ac_soapclient_parse_json_response(response); + if (!jsonroot) { + return CAPWAP_RESULTCODE_FAILURE; + } /* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */ diff --git a/src/ac/ac_dfa_join.c b/src/ac/ac_dfa_join.c index 288ec12..033b967 100644 --- a/src/ac/ac_dfa_join.c +++ b/src/ac/ac_dfa_join.c @@ -321,18 +321,12 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session, int i; int j; int length; - char* json; - xmlChar* xmlResult; struct json_object* jsonroot; struct json_object* jsonelement; struct capwap_list* controllist; struct capwap_list_item* item; unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header); - if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { - return CAPWAP_RESULTCODE_FAILURE; - } - /* Receive SOAP response with JSON result { WTPRadioInformation: [ @@ -364,28 +358,11 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session, } */ - /* Decode base64 result */ - xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (!xmlResult) { - return CAPWAP_RESULTCODE_FAILURE; - } - - length = xmlStrlen(xmlResult); - if (!length) { - xmlFree(xmlResult); - return CAPWAP_RESULTCODE_FAILURE; - } - - json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); - ac_base64_string_decode((const char*)xmlResult, json); - - xmlFree(xmlResult); - - /* Parsing JSON result */ - jsonroot = json_tokener_parse(json); - capwap_free(json); - /* Add message elements response, every local value can be overwrite from backend server */ + jsonroot = ac_soapclient_parse_json_response(response); + if (!jsonroot) { + return CAPWAP_RESULTCODE_FAILURE; + } /* AC Descriptor */ ac_update_statistics(); diff --git a/src/ac/ac_execute.c b/src/ac/ac_execute.c index 6ff7d42..1d19508 100644 --- a/src/ac/ac_execute.c +++ b/src/ac/ac_execute.c @@ -7,8 +7,151 @@ #include +#define MAX_MTU 9000 +#define MIN_MTU 500 + #define AC_RECV_NOERROR_MSGQUEUE -1001 #define AC_RECV_NOERROR_KMODEVENT -1002 +#define AC_RECV_NOERROR_BACKENDNOCONNECT -1003 + +#define AC_IFACE_MAX_INDEX 256 +#define AC_IFACE_NAME "capwap%lu" + +/* */ +static void ac_close_sessions(void); + +/* */ +static int ac_update_configuration_create_datachannelinterfaces(struct ac_if_datachannel* datachannel) { + /* Create virtual interface */ + sprintf(datachannel->ifname, AC_IFACE_NAME, datachannel->index); + datachannel->ifindex = ac_kmod_create_iface(datachannel->ifname, datachannel->mtu); + if (datachannel->ifindex < 0) { + return datachannel->ifindex; + } + + /* TODO manage bridge */ + + return 0; +} + +/* */ +static int ac_update_configuration_getdatachannel_params(struct json_object* jsonvalue, int* mtu, const char** bridge) { + int result = -1; + struct json_object* jsonmtu; + + /* */ + jsonmtu = compat_json_object_object_get(jsonvalue, "MTU"); + if (jsonmtu && (json_object_get_type(jsonmtu) == json_type_int)) { + *mtu = json_object_get_int(jsonmtu); + if ((*mtu >= MIN_MTU) && (*mtu <= MAX_MTU)) { + struct json_object* jsonbridge = compat_json_object_object_get(jsonvalue, "Bridge"); + + *bridge = ((jsonbridge && (json_object_get_type(jsonmtu) == json_type_string)) ? json_object_get_string(jsonbridge) : NULL); + result = 0; + } + } + + return result; +} + +/* */ +static int ac_update_configuration_datachannelinterfaces(void* data, void* param) { + int i; + int mtu; + int length; + const char* bridge; + struct ac_if_datachannel* iface = (struct ac_if_datachannel*)data; + struct array_list* interfaces = (struct array_list*)param; + + /* Search interface */ + length = array_list_length(interfaces); + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = array_list_get_idx(interfaces, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { + struct json_object* jsonindex = compat_json_object_object_get(jsonvalue, "Index"); + if (jsonindex && (json_object_get_type(jsonindex) == json_type_int)) { + if (iface->index == (unsigned long)json_object_get_int(jsonindex)) { + if (!ac_update_configuration_getdatachannel_params(jsonvalue, &mtu, &bridge)) { + /* TODO */ + } + + /* Interface found */ + array_list_put_idx(interfaces, i, NULL); + break; + } + } + } + } + + return ((i == length) ? HASH_DELETE_AND_CONTINUE : HASH_CONTINUE); +} + +/* */ +static void ac_update_configuration(struct json_object* jsonroot) { + int i; + int mtu; + int length; + const char* bridge; + struct json_object* jsonelement; + struct ac_if_datachannel* datachannel; + + ASSERT(jsonroot != NULL); + + /* Params + { + DataChannelInterfaces: [ + { + Index: [int], + MTU: [int], + Bridge: [string] + } + ] + } + */ + + /* DataChannelInterfaces */ + jsonelement = compat_json_object_object_get(jsonroot, "DataChannelInterfaces"); + if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { + struct array_list* interfaces = json_object_get_array(jsonelement); + + capwap_rwlock_wrlock(&g_ac.ifdatachannellock); + + /* Update and Remove active interfaces*/ + capwap_hash_foreach(g_ac.ifdatachannel, ac_update_configuration_datachannelinterfaces, interfaces); + + /* Add new interfaces*/ + length = array_list_length(interfaces); + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = array_list_get_idx(interfaces, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { + struct json_object* jsonindex = compat_json_object_object_get(jsonvalue, "Index"); + if (jsonindex && (json_object_get_type(jsonindex) == json_type_int)) { + int index = json_object_get_int(jsonindex); + if ((index >= 0) && (index < AC_IFACE_MAX_INDEX) && !ac_update_configuration_getdatachannel_params(jsonvalue, &mtu, &bridge)) { + datachannel = (struct ac_if_datachannel*)capwap_alloc(sizeof(struct ac_if_datachannel)); + memset(datachannel, 0, sizeof(struct ac_if_datachannel)); + + /* */ + datachannel->index = (unsigned long)index; + datachannel->mtu = mtu; + if (bridge && (strlen(bridge) < IFNAMSIZ)) { + strcpy(datachannel->bridge, bridge); + } + + /* */ + if (!ac_update_configuration_create_datachannelinterfaces(datachannel)) { + capwap_hash_add(g_ac.ifdatachannel, (void*)datachannel); + } else { + capwap_free(datachannel); + } + } + } + } + } + + capwap_rwlock_unlock(&g_ac.ifdatachannellock); + } +} /* */ static int ac_recvmsgqueue(int fd, struct ac_session_msgqueue_item_t* item) { @@ -46,6 +189,19 @@ static void ac_session_msgqueue_parsing_item(struct ac_session_msgqueue_item_t* break; } + case AC_MESSAGE_QUEUE_UPDATE_CONFIGURATION: { + ac_update_configuration(item->message_configuration.jsonroot); + + /* Free JSON */ + json_object_put(item->message_configuration.jsonroot); + break; + } + + case AC_MESSAGE_QUEUE_CLOSE_ALLSESSIONS: { + ac_close_sessions(); /* Close all sessions */ + break; + } + default: { capwap_logging_debug("Unknown message queue item: %lu", item->message); break; @@ -92,7 +248,7 @@ void ac_msgqueue_free(void) { } /* */ -void ac_msgqueue_notify_closethread(pthread_t threadid) { +int ac_msgqueue_notify_closethread(pthread_t threadid) { struct ac_session_msgqueue_item_t item; /* Send message */ @@ -101,6 +257,32 @@ void ac_msgqueue_notify_closethread(pthread_t threadid) { item.message_close_thread.threadid = threadid; send(g_ac.fdmsgsessions[0], (void*)&item, sizeof(struct ac_session_msgqueue_item_t), 0); + return ((send(g_ac.fdmsgsessions[0], (void*)&item, sizeof(struct ac_session_msgqueue_item_t), 0) == sizeof(struct ac_session_msgqueue_item_t)) ? 0 : -1); +} + +/* */ +int ac_msgqueue_update_configuration(struct json_object* jsonroot) { + struct ac_session_msgqueue_item_t item; + + ASSERT(jsonroot != NULL); + + /* Send message */ + memset(&item, 0, sizeof(struct ac_session_msgqueue_item_t)); + item.message = AC_MESSAGE_QUEUE_UPDATE_CONFIGURATION; + item.message_configuration.jsonroot = jsonroot; + + return ((send(g_ac.fdmsgsessions[0], (void*)&item, sizeof(struct ac_session_msgqueue_item_t), 0) == sizeof(struct ac_session_msgqueue_item_t)) ? 0 : -1); +} + +/* */ +int ac_msgqueue_close_allsessions(void) { + struct ac_session_msgqueue_item_t item; + + /* Send message */ + memset(&item, 0, sizeof(struct ac_session_msgqueue_item_t)); + item.message = AC_MESSAGE_QUEUE_CLOSE_ALLSESSIONS; + + return ((send(g_ac.fdmsgsessions[0], (void*)&item, sizeof(struct ac_session_msgqueue_item_t), 0) == sizeof(struct ac_session_msgqueue_item_t)) ? 0 : -1); } /* */ @@ -142,6 +324,8 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, union sockad /* Parsing message queue packet */ ac_session_msgqueue_parsing_item(&item); return AC_RECV_NOERROR_MSGQUEUE; + } else if (!ac_backend_isconnect()) { + return AC_RECV_NOERROR_BACKENDNOCONNECT; } /* Receive packet */ @@ -213,7 +397,7 @@ void ac_session_send_action(struct ac_session_t* session, long action, long para search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); } /* Find AC sessions */ @@ -245,7 +429,7 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(union sockaddr_cap search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); return result; } @@ -279,7 +463,7 @@ struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) { search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); return result; } @@ -313,7 +497,7 @@ struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_el search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); return result; } @@ -340,7 +524,7 @@ int ac_has_sessionid(struct capwap_sessionid_element* sessionid) { search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); return result; } @@ -369,7 +553,7 @@ int ac_has_wtpid(const char* wtpid) { search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); return result; } @@ -402,7 +586,7 @@ void ac_session_close(struct ac_session_t* session) { } /* Close sessions */ -static void ac_close_sessions() { +static void ac_close_sessions(void) { struct capwap_list_item* search; capwap_rwlock_rdlock(&g_ac.sessionslock); @@ -418,7 +602,7 @@ static void ac_close_sessions() { search = search->next; } - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); } /* Create new session */ @@ -483,7 +667,7 @@ static struct ac_session_t* ac_create_session(int sock, union sockaddr_capwap* f /* Update session list */ capwap_rwlock_wrlock(&g_ac.sessionslock); capwap_itemlist_insert_after(g_ac.sessions, NULL, itemlist); - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); /* Create thread */ result = pthread_create(&session->threadid, NULL, ac_session_thread, (void*)session); @@ -523,7 +707,7 @@ void ac_update_statistics(void) { capwap_rwlock_rdlock(&g_ac.sessionslock); g_ac.descriptor.activewtp = g_ac.sessions->count; - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); } /* Handler signal */ @@ -697,7 +881,7 @@ int ac_execute(void) { /* Get current session number */ capwap_rwlock_rdlock(&g_ac.sessionslock); sessioncount = g_ac.sessions->count; - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); /* */ if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) { @@ -737,12 +921,8 @@ int ac_execute(void) { } } } - } else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE) || (index == AC_RECV_NOERROR_KMODEVENT)) { - /* Ignore recv */ - continue; } else if (index == CAPWAP_RECV_ERROR_SOCKET) { - /* Socket close */ - break; + break; /* Socket close */ } } @@ -758,6 +938,9 @@ int ac_execute(void) { /* Wait to terminate all sessions */ ac_wait_terminate_allsessions(); + /* Close data channel interfaces */ + capwap_hash_deleteall(g_ac.ifdatachannel); + /* Free Backend Management */ ac_backend_free(); diff --git a/src/ac/ac_session.c b/src/ac/ac_session.c index b0a8d2b..ec51b24 100644 --- a/src/ac/ac_session.c +++ b/src/ac/ac_session.c @@ -9,6 +9,71 @@ #define AC_NO_ERROR -1000 #define AC_ERROR_TIMEOUT -1001 +/* */ +static struct ac_soap_response* ac_session_action_authorizestation_request(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid, uint8_t* address) { + const char* jsonmessage; + char* base64confstatus; + struct json_object* jsonparam; + struct ac_soap_response* response; + char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + /* Create SOAP request with JSON param + { + RadioID: [int], + WLANID: [int], + Station: [string], + } + */ + + /* */ + jsonparam = json_object_new_object(); + + /* RadioID */ + json_object_object_add(jsonparam, "RadioID", json_object_new_int((int)radioid)); + + /* WLANID */ + json_object_object_add(jsonparam, "WLANID", json_object_new_int((int)wlanid)); + + /* Station */ + json_object_object_add(jsonparam, "Station", json_object_new_string(capwap_printf_macaddress(addrtext, address, MACADDRESS_EUI48_LENGTH))); + + /* Get JSON param and convert base64 */ + jsonmessage = json_object_to_json_string(jsonparam); + base64confstatus = capwap_alloc(AC_BASE64_ENCODE_LENGTH(strlen(jsonmessage))); + ac_base64_string_encode(jsonmessage, base64confstatus); + + /* Send message */ + response = ac_soap_authorizestation(session, session->wtpid, base64confstatus); + + /* Free JSON */ + json_object_put(jsonparam); + capwap_free(base64confstatus); + + return response; +} + +/* */ +static int ac_session_action_authorizestation_response(struct ac_session_t* session, struct ac_soap_response* response) { + struct json_object* jsonroot; + + /* Receive SOAP response with JSON result + { + } + */ + + /* */ + jsonroot = ac_soapclient_parse_json_response(response); + if (!jsonroot) { + return -1; + } + + /* TODO */ + + /* */ + json_object_put(jsonroot); + return 0; +} + /* */ static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_notify_reset_t* reset) { struct capwap_header_data capwapheader; @@ -63,10 +128,8 @@ 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_NO_ERROR; -#if 0 } else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) { return AC_NO_ERROR; -#endif } /* */ @@ -120,6 +183,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a struct capwap_packet_txmng* txmngpacket; struct capwap_addstation_element addstation; struct capwap_80211_station_element station; + struct ac_soap_response* response; ASSERT(session->requestfragmentpacket->count == 0); @@ -129,51 +193,60 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a } /* */ - memset(&addstation, 0, sizeof(struct capwap_addstation_element)); - addstation.radioid = notify->radioid; - addstation.length = MACADDRESS_EUI48_LENGTH; - addstation.address = notify->address; - if (notify->vlan[0]) { - addstation.vlan = notify->vlan; - } + response = ac_session_action_authorizestation_request(session, notify->radioid, notify->wlanid, notify->address); + if (response) { + if (!ac_session_action_authorizestation_response(session, response)) { + memset(&addstation, 0, sizeof(struct capwap_addstation_element)); + addstation.radioid = notify->radioid; + addstation.length = MACADDRESS_EUI48_LENGTH; + addstation.address = notify->address; + if (notify->vlan[0]) { + addstation.vlan = notify->vlan; + } - /* */ - memset(&station, 0, sizeof(struct capwap_80211_station_element)); - station.radioid = notify->radioid; - station.associationid = notify->associationid; - memcpy(station.address, notify->address, MACADDRESS_EUI48_LENGTH); - station.capabilities = notify->capabilities; - station.wlanid = notify->wlanid; - station.supportedratescount = notify->supportedratescount; - memcpy(station.supportedrates, notify->supportedrates, station.supportedratescount); + /* */ + memset(&station, 0, sizeof(struct capwap_80211_station_element)); + station.radioid = notify->radioid; + station.associationid = notify->associationid; + memcpy(station.address, notify->address, MACADDRESS_EUI48_LENGTH); + station.capabilities = notify->capabilities; + station.wlanid = notify->wlanid; + station.supportedratescount = notify->supportedratescount; + memcpy(station.supportedrates, notify->supportedrates, station.supportedratescount); - /* Build packet */ - capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, session->binding); - txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, CAPWAP_STATION_CONFIGURATION_REQUEST, session->localseqnumber++, session->mtu); + /* Build packet */ + capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, session->binding); + txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, CAPWAP_STATION_CONFIGURATION_REQUEST, session->localseqnumber++, session->mtu); + + /* Add message element */ + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ADDSTATION, &addstation); + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_STATION, &station); - /* Add message element */ - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ADDSTATION, &addstation); - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_STATION, &station); + /* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */ - /* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */ + /* Station Configuration Request complete, get fragment packets */ + capwap_packet_txmng_get_fragment_packets(txmngpacket, session->requestfragmentpacket, session->fragmentid); + if (session->requestfragmentpacket->count > 1) { + session->fragmentid++; + } - /* Station Configuration Request complete, get fragment packets */ - capwap_packet_txmng_get_fragment_packets(txmngpacket, session->requestfragmentpacket, session->fragmentid); - if (session->requestfragmentpacket->count > 1) { - session->fragmentid++; - } + /* Free packets manager */ + capwap_packet_txmng_free(txmngpacket); - /* Free packets manager */ - capwap_packet_txmng_free(txmngpacket); + /* Send Station Configuration Request to WTP */ + 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 { + capwap_logging_debug("Warning: error to send Station Configuration Request packet"); + ac_free_reference_last_request(session); + ac_session_teardown(session); + } + } else { + /* TODO kickoff station */ + } - /* Send Station Configuration Request to WTP */ - 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 { - capwap_logging_debug("Warning: error to send Station Configuration Request packet"); - ac_free_reference_last_request(session); - ac_session_teardown(session); + ac_soapclient_free_response(response); } return AC_NO_ERROR; @@ -793,7 +866,7 @@ void ac_session_teardown(struct ac_session_t* session) { /* Remove session from list */ capwap_rwlock_wrlock(&g_ac.sessionslock); capwap_itemlist_remove(g_ac.sessions, session->itemlist); - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); /* Remove all pending packets */ while (session->packets->count > 0) { @@ -872,7 +945,7 @@ void ac_get_control_information(struct capwap_list* controllist) { /* */ capwap_rwlock_rdlock(&g_ac.sessionslock); count = g_ac.sessions->count; - capwap_rwlock_exit(&g_ac.sessionslock); + capwap_rwlock_unlock(&g_ac.sessionslock); /* Prepare control list */ for (item = g_ac.addrlist->first; item != NULL; item = item->next) { diff --git a/src/ac/ac_session.h b/src/ac/ac_session.h index dc53adb..89bd261 100644 --- a/src/ac/ac_session.h +++ b/src/ac/ac_session.h @@ -184,7 +184,11 @@ void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const st /* */ int ac_msgqueue_init(void); void ac_msgqueue_free(void); -void ac_msgqueue_notify_closethread(pthread_t threadid); + +/* */ +int ac_msgqueue_notify_closethread(pthread_t threadid); +int ac_msgqueue_update_configuration(struct json_object* jsonroot); +int ac_msgqueue_close_allsessions(void); /* */ int ac_dtls_setup(struct ac_session_t* session); @@ -213,5 +217,6 @@ struct ac_soap_response* ac_session_send_soap_request(struct ac_session_t* sessi #define ac_soap_teardownwtpsession(s, wtpid) ac_session_send_soap_request((s), "teardownWTPSession", 1, "xs:string", "idwtp", wtpid) #define ac_soap_checkwtpsession(s, wtpid) ac_session_send_soap_request((s), "checkWTPSession", 1, "xs:string", "idwtp", wtpid) #define ac_soap_updatebackendevent(s, idevent, status) ac_session_send_soap_request((s), "updateBackendEvent", 2, "xs:string", "idevent", idevent, "xs:int", "status", status) +#define ac_soap_authorizestation(s, wtpid, stationparam) ac_session_send_soap_request((s), "authorizeStation", 2, "xs:string", "idwtp", wtpid, "xs:base64Binary", "station", stationparam) #endif /* __AC_SESSION_HEADER__ */ diff --git a/src/ac/ac_soap.c b/src/ac/ac_soap.c index c2a38fc..f0fb8d8 100644 --- a/src/ac/ac_soap.c +++ b/src/ac/ac_soap.c @@ -721,6 +721,44 @@ struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request return response; } +/* */ +struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response) { + int length; + char* json; + xmlChar* xmlResult; + struct json_object* jsonroot; + + ASSERT(response != NULL); + + /* */ + if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { + return NULL; + } + + /* Decode base64 result */ + xmlResult = xmlNodeGetContent(response->xmlResponseReturn); + if (!xmlResult) { + return NULL; + } + + length = xmlStrlen(xmlResult); + if (!length) { + xmlFree(xmlResult); + return NULL; + } + + json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); + ac_base64_string_decode((const char*)xmlResult, json); + + xmlFree(xmlResult); + + /* Parsing JSON result */ + jsonroot = json_tokener_parse(json); + capwap_free(json); + + return jsonroot; +} + /* */ void ac_soapclient_free_response(struct ac_soap_response* response) { ASSERT(response != NULL); diff --git a/src/ac/ac_soap.h b/src/ac/ac_soap.h index 027c077..c563177 100644 --- a/src/ac/ac_soap.h +++ b/src/ac/ac_soap.h @@ -95,6 +95,8 @@ struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_reques int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* soapaction); struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request* httprequest); +struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response); + void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest); void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int closerequest); diff --git a/src/ac/ac_wlans.c b/src/ac/ac_wlans.c index 3589122..326e777 100644 --- a/src/ac/ac_wlans.c +++ b/src/ac/ac_wlans.c @@ -3,25 +3,6 @@ #include "ac_wlans.h" #include "ac_backend.h" -/* */ -static void ac_stations_delete_station_from_global_cache(struct ac_session_t* session, uint8_t* address) { - struct ac_session_t* ownersession; - - ASSERT(session != NULL); - ASSERT(address != NULL); - - /* */ - capwap_rwlock_wrlock(&g_ac.stationslock); - - /* Can delete global reference only if match session handler */ - ownersession = (struct ac_session_t*)capwap_hash_search(g_ac.stations, address); - if (ownersession == session) { - capwap_hash_delete(g_ac.stations, address); - } - - capwap_rwlock_exit(&g_ac.stationslock); -} - /* */ static void ac_stations_reset_station(struct ac_session_t* session, struct ac_station* station, struct ac_wlan* wlan) { ASSERT(session != NULL); @@ -58,14 +39,24 @@ static void ac_stations_reset_station(struct ac_session_t* session, struct ac_st /* */ static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_station* station) { + struct ac_station* authoritativestation; + ASSERT(session != NULL); ASSERT(station != NULL); /* */ capwap_logging_info("Destroy station: %s", station->addrtext); - /* Remove reference from Global Cache Stations List */ - ac_stations_delete_station_from_global_cache(session, station->address); + /* Remove reference from Authoritative Stations List */ + capwap_rwlock_wrlock(&g_ac.authstationslock); + + /* Can delete global reference only if match session handler */ + authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, station->address); + if (authoritativestation && (authoritativestation->session == session)) { + capwap_hash_delete(g_ac.authstations, station->address); + } + + capwap_rwlock_unlock(&g_ac.authstationslock); /* Remove reference from WLAN */ ac_stations_reset_station(session, station, NULL); @@ -78,14 +69,22 @@ static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_ } /* */ -static unsigned long ac_wlans_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { +static unsigned long ac_wlans_item_gethash(const void* key, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; - ASSERT(keysize == MACADDRESS_EUI48_LENGTH); - return (unsigned long)(macaddress[3] ^ macaddress[4] ^ macaddress[5]); } +/* */ +static const void* ac_wlans_item_getkey(const void* data) { + return (const void*)((struct ac_station*)data)->address; +} + +/* */ +static int ac_wlans_item_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + /* */ void ac_wlans_init(struct ac_session_t* session) { int i; @@ -98,7 +97,11 @@ void ac_wlans_init(struct ac_session_t* session) { memset(session->wlans, 0, sizeof(struct ac_wlans)); /* */ - session->wlans->stations = capwap_hash_create(AC_WLANS_STATIONS_HASH_SIZE, AC_WLANS_STATIONS_KEY_SIZE, ac_wlans_item_gethash, NULL, NULL); + session->wlans->stations = capwap_hash_create(AC_WLANS_STATIONS_HASH_SIZE); + session->wlans->stations->item_gethash = ac_wlans_item_gethash; + session->wlans->stations->item_getkey = ac_wlans_item_getkey; + session->wlans->stations->item_cmp = ac_wlans_item_cmp; + for (i = 0; i < RADIOID_MAX_COUNT; i++) { session->wlans->devices[i].radioid = i + 1; } @@ -326,9 +329,9 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint char buffer1[CAPWAP_MACADDRESS_EUI48_BUFFER]; char buffer2[CAPWAP_MACADDRESS_EUI48_BUFFER]; struct ac_wlan* wlan; - struct ac_session_t* ownersession; - struct capwap_list_item* stationitem; + struct ac_station* authoritativestation; struct ac_station* station = NULL; + struct ac_session_t* authoritativesession = NULL; ASSERT(session != NULL); ASSERT(session->wlans != NULL); @@ -344,28 +347,10 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint /* */ wlan = ac_wlans_get_bssid(session, radioid, bssid); if (wlan) { - /* Get session that owns the station */ - capwap_rwlock_rdlock(&g_ac.stationslock); - ownersession = (struct ac_session_t*)capwap_hash_search(g_ac.stations, address); - capwap_rwlock_exit(&g_ac.stationslock); - - /* If request change owner of station */ - if (ownersession != session) { - /* Release station from old owner */ - if (ownersession) { - ac_session_send_action(ownersession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH); - } - - /* Set station into Global Cache Stations List */ - capwap_rwlock_wrlock(&g_ac.stationslock); - capwap_hash_add(g_ac.stations, address, session); - capwap_rwlock_exit(&g_ac.stationslock); - } - - /* */ station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); if (!station) { - stationitem = capwap_itemlist_create(sizeof(struct ac_station)); + struct capwap_list_item* stationitem = capwap_itemlist_create(sizeof(struct ac_station)); + station = (struct ac_station*)stationitem->item; memset(station, 0, sizeof(struct ac_station)); @@ -374,14 +359,38 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); station->wlanitem = stationitem; + station->session = session; /* */ - capwap_hash_add(session->wlans->stations, address, station); + capwap_hash_add(session->wlans->stations, (void*)station); } /* Set station to WLAN */ ac_stations_reset_station(session, station, wlan); station->flags |= AC_STATION_FLAGS_ENABLED; + + /* Check Authoritative Stations List */ + capwap_rwlock_rdlock(&g_ac.authstationslock); + + authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, address); + if (authoritativestation && authoritativestation->session) { + authoritativesession = authoritativestation->session; + } + + capwap_rwlock_unlock(&g_ac.authstationslock); + + /* Check Authoritative Session */ + if (authoritativesession != session) { + /* Update Authoritative Stations List */ + capwap_rwlock_wrlock(&g_ac.authstationslock); + capwap_hash_add(g_ac.authstations, (void*)station); + capwap_rwlock_unlock(&g_ac.authstationslock); + + /* Release Station from old Authoritative Session */ + if (authoritativesession) { + ac_session_send_action(authoritativesession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH); + } + } } else { capwap_logging_warning("Unable to find radioid: %d, bssid: %s", (int)radioid, buffer1); } diff --git a/src/ac/ac_wlans.h b/src/ac/ac_wlans.h index 93802c0..ec47417 100644 --- a/src/ac/ac_wlans.h +++ b/src/ac/ac_wlans.h @@ -83,6 +83,9 @@ struct ac_station { struct ac_wlan* wlan; struct capwap_list_item* wlanitem; + /* Reference of Session */ + struct ac_session_t* session; + /* Timers */ int timeoutaction; unsigned long idtimeout; diff --git a/src/ac/kmod/iface.c b/src/ac/kmod/iface.c index 4c7d6c3..998f989 100644 --- a/src/ac/kmod/iface.c +++ b/src/ac/kmod/iface.c @@ -26,6 +26,8 @@ static void sc_iface_netdev_uninit(struct net_device* dev) { int hash = CAPWAP_IFACE_HASH(dev->ifindex); struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); + TRACEKMOD("### sc_iface_netdev_uninit\n"); + /* Remove interface from hash */ spin_lock_irqsave(&sc_iface_lock, flags); @@ -66,24 +68,32 @@ static void sc_iface_netdev_uninit(struct net_device* dev) { /* */ static int sc_iface_netdev_open(struct net_device* dev) { + TRACEKMOD("### sc_iface_netdev_open\n"); + netif_start_queue(dev); return 0; } /* */ static int sc_iface_netdev_stop(struct net_device* dev) { + TRACEKMOD("### sc_iface_netdev_stop\n"); + netif_stop_queue(dev); return 0; } /* */ static int sc_iface_netdev_tx(struct sk_buff* skb, struct net_device* dev) { + TRACEKMOD("### sc_iface_netdev_tx\n"); + /* TODO */ return 0; } /* */ static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) { + TRACEKMOD("### sc_iface_netdev_change_mtu\n"); + /* TODO */ return 0; } @@ -92,6 +102,8 @@ static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) { static void sc_iface_netdev_setup(struct net_device* dev) { struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); + TRACEKMOD("### sc_iface_netdev_setup\n"); + /* */ memset(priv, 0, sizeof(struct sc_netdev_priv)); priv->dev = dev; @@ -114,6 +126,8 @@ int sc_iface_create(const char* ifname, uint16_t mtu) { struct net_device* dev; struct sc_netdev_priv* priv; + TRACEKMOD("### sc_iface_create\n"); + /* Create interface */ dev = alloc_netdev(sizeof(struct sc_netdev_priv), ifname, sc_iface_netdev_setup); if (!dev) { @@ -164,6 +178,8 @@ int sc_iface_delete(uint32_t ifindex) { unsigned long flags; struct sc_netdev_priv* priv; + TRACEKMOD("### sc_iface_delete\n"); + /* */ spin_lock_irqsave(&sc_iface_lock, flags); @@ -195,6 +211,8 @@ void sc_iface_closeall(void) { int i; unsigned long flags; + TRACEKMOD("### sc_iface_closeall\n"); + while (sc_iface_count) { struct net_device* dev = NULL; diff --git a/src/ac/kmod/netlinkapp.c b/src/ac/kmod/netlinkapp.c index 56300c9..b17e643 100644 --- a/src/ac/kmod/netlinkapp.c +++ b/src/ac/kmod/netlinkapp.c @@ -291,7 +291,11 @@ static int sc_netlink_delete_iface(struct sk_buff* skb, struct genl_info* info) } /* */ - return 0; + if (!info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) { + return -EINVAL; + } + + return sc_iface_delete(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX])); } /* */ diff --git a/src/common/capwap_hash.c b/src/common/capwap_hash.c index 270f638..aed0548 100644 --- a/src/common/capwap_hash.c +++ b/src/common/capwap_hash.c @@ -5,13 +5,11 @@ static void capwap_hash_free_item(struct capwap_hash* hash, struct capwap_hash_item* item) { ASSERT(hash != NULL); ASSERT(item != NULL); - ASSERT(item->key != NULL); if (item->data && hash->item_free) { - hash->item_free(item->key, hash->keysize, item->data); + hash->item_free(item->data); } - capwap_free(item->key); capwap_free(item); } @@ -43,7 +41,7 @@ static struct capwap_hash_item* capwap_hash_search_items(struct capwap_hash* has search = item; while (search) { - result = hash->item_cmp(key, search->key, hash->keysize); + result = hash->item_cmp(key, hash->item_getkey(search->data)); if (!result) { return search; @@ -59,44 +57,57 @@ static struct capwap_hash_item* capwap_hash_search_items(struct capwap_hash* has /* */ static int capwap_hash_foreach_items(struct capwap_hash* hash, struct capwap_hash_item* item, capwap_hash_item_foreach item_foreach, void* param) { + int result; + ASSERT(hash != NULL); ASSERT(item_foreach != NULL); ASSERT(item != NULL); /* */ if (item->left) { - if (!capwap_hash_foreach_items(hash, item->left, item_foreach, param)) { - return 0; + result = capwap_hash_foreach_items(hash, item->left, item_foreach, param); + if (result == HASH_BREAK) { + return HASH_BREAK; } } /* */ - if (!item_foreach(item->key, hash->keysize, item->data, param)) { - return 0; + item->removenext = NULL; + result = item_foreach(item->data, param); + + /* Delete item */ + if ((result == HASH_DELETE_AND_BREAK) || (result == HASH_DELETE_AND_CONTINUE)) { + item->removenext = hash->removeitems; + hash->removeitems = item; + } + + /* Break */ + if ((result == HASH_BREAK) || (result == HASH_DELETE_AND_BREAK)) { + return HASH_BREAK; } /* */ if (item->right) { - if (!capwap_hash_foreach_items(hash, item->right, item_foreach, param)) { - return 0; + result = capwap_hash_foreach_items(hash, item->right, item_foreach, param); + if (result == HASH_BREAK) { + return HASH_BREAK; } } - return 1; + return HASH_CONTINUE; } /* */ -static struct capwap_hash_item* capwap_hash_create_item(struct capwap_hash* hash, const void* key, void* data) { +static struct capwap_hash_item* capwap_hash_create_item(struct capwap_hash* hash, void* data) { struct capwap_hash_item* item; ASSERT(hash != NULL); - ASSERT(key != NULL); + ASSERT(data != NULL); /* */ item = (struct capwap_hash_item*)capwap_alloc(sizeof(struct capwap_hash_item)); memset(item, 0, sizeof(struct capwap_hash_item)); - item->key = capwap_clone(key, hash->keysize); item->data = data; return item; @@ -243,132 +254,13 @@ static void capwap_hash_balance_tree(struct capwap_hash_item* item, struct capwa } /* */ -static int capwap_hash_item_memcmp(const void* key1, const void* key2, unsigned long keysize) { - return memcmp(key1, key2, keysize); -} - -/* */ -struct capwap_hash* capwap_hash_create(unsigned long hashsize, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free) { - unsigned long size; - struct capwap_hash* hash; - - ASSERT(hashsize > 0); - ASSERT(keysize > 0); - ASSERT(item_hash != NULL); - - size = sizeof(struct capwap_hash_item*) * hashsize; - - /* */ - hash = (struct capwap_hash*)capwap_alloc(sizeof(struct capwap_hash)); - hash->hashsize = hashsize; - hash->keysize = keysize; - hash->count = 0; - hash->items = (struct capwap_hash_item**)capwap_alloc(size); - memset(hash->items, 0, size); - hash->item_hash = item_hash; - hash->item_cmp = (item_cmp ? item_cmp : capwap_hash_item_memcmp); - hash->item_free = item_free; - - return hash; -} - -/* */ -void capwap_hash_free(struct capwap_hash* hash) { - ASSERT(hash != NULL); - - /* Delete all items */ - capwap_hash_deleteall(hash); - - /* Free */ - capwap_free(hash->items); - capwap_free(hash); -} - -/* */ -void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data) { - int result; - unsigned long hashvalue; - struct capwap_hash_item* search; - struct capwap_hash_item* item = NULL; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - - /* */ - hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); - ASSERT(hashvalue < hash->hashsize); - - /* Search position where insert item */ - search = hash->items[hashvalue]; - if (!search) { - hash->count++; - hash->items[hashvalue] = capwap_hash_create_item(hash, key, data); - } else { - while (search) { - result = hash->item_cmp(key, search->key, hash->keysize); - if (!result) { - /* Free old element and update data value without create new item */ - if (search->data && hash->item_free) { - hash->item_free(search->key, hash->keysize, search->data); - } - - search->data = data; - break; - } else if (result < 0) { - if (search->left) { - search = search->left; - } else { - hash->count++; - item = capwap_hash_create_item(hash, key, data); - capwap_hash_set_left_item(search, item); - break; - } - } else if (result > 0) { - if (search->right) { - search = search->right; - } else { - hash->count++; - item = capwap_hash_create_item(hash, key, data); - capwap_hash_set_right_item(search, item); - break; - } - } - } - - /* Rebalancing tree */ - while (item) { - capwap_hash_update_height(item); - capwap_hash_balance_tree(item, &hash->items[hashvalue]); - - /* Rebalancing parent */ - item = item->parent; - } - } -} - -/* */ -void capwap_hash_delete(struct capwap_hash* hash, const void* key) { - unsigned long hashvalue; - struct capwap_hash_item* search; +static void capwap_hash_deleteitem(struct capwap_hash* hash, const void* key, struct capwap_hash_item* search, unsigned long hashvalue) { struct capwap_hash_item* parent; ASSERT(hash != NULL); ASSERT(key != NULL); - - /* */ - hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); - if (!hash->items[hashvalue]) { - return; - } - - /* */ - search = capwap_hash_search_items(hash, hash->items[hashvalue], key); - if (!search) { - return; - } - - /* */ - ASSERT(hash->count > 0); + ASSERT(search != NULL); + ASSERT(hashvalue < hash->hashsize); /* Rebalancing tree */ parent = search->parent; @@ -465,6 +357,129 @@ void capwap_hash_delete(struct capwap_hash* hash, const void* key) { capwap_hash_free_item(hash, search); } +/* */ +struct capwap_hash* capwap_hash_create(unsigned long hashsize) { + unsigned long size; + struct capwap_hash* hash; + + ASSERT(hashsize > 0); + + /* */ + hash = (struct capwap_hash*)capwap_alloc(sizeof(struct capwap_hash)); + hash->hashsize = hashsize; + hash->count = 0; + + size = sizeof(struct capwap_hash_item*) * hashsize; + hash->items = (struct capwap_hash_item**)capwap_alloc(size); + memset(hash->items, 0, size); + + return hash; +} + +/* */ +void capwap_hash_free(struct capwap_hash* hash) { + ASSERT(hash != NULL); + + /* Delete all items */ + capwap_hash_deleteall(hash); + + /* Free */ + capwap_free(hash->items); + capwap_free(hash); +} + +/* */ +void capwap_hash_add(struct capwap_hash* hash, void* data) { + int result; + const void* key; + unsigned long hashvalue; + struct capwap_hash_item* search; + struct capwap_hash_item* item = NULL; + + ASSERT(data != NULL); + ASSERT(hash != NULL); + ASSERT(hash->item_gethash != NULL); + ASSERT(hash->item_getkey != NULL); + ASSERT(hash->item_cmp != NULL); + + /* */ + key = hash->item_getkey(data); + hashvalue = hash->item_gethash(key, hash->hashsize); + ASSERT(hashvalue < hash->hashsize); + + /* Search position where insert item */ + search = hash->items[hashvalue]; + if (!search) { + hash->count++; + hash->items[hashvalue] = capwap_hash_create_item(hash, data); + } else { + while (search) { + result = hash->item_cmp(key, hash->item_getkey(search->data)); + if (!result) { + /* Free old element and update data value without create new item */ + if (search->data && hash->item_free) { + hash->item_free(search->data); + } + + search->data = data; + break; + } else if (result < 0) { + if (search->left) { + search = search->left; + } else { + hash->count++; + item = capwap_hash_create_item(hash, data); + capwap_hash_set_left_item(search, item); + break; + } + } else if (result > 0) { + if (search->right) { + search = search->right; + } else { + hash->count++; + item = capwap_hash_create_item(hash, data); + capwap_hash_set_right_item(search, item); + break; + } + } + } + + /* Rebalancing tree */ + while (item) { + capwap_hash_update_height(item); + capwap_hash_balance_tree(item, &hash->items[hashvalue]); + + /* Rebalancing parent */ + item = item->parent; + } + } +} + +/* */ +void capwap_hash_delete(struct capwap_hash* hash, const void* key) { + unsigned long hashvalue; + struct capwap_hash_item* search; + + ASSERT(hash != NULL); + ASSERT(key != NULL); + + /* */ + hashvalue = hash->item_gethash(key, hash->hashsize); + ASSERT(hashvalue < hash->hashsize); + if (!hash->items[hashvalue]) { + return; + } + + /* */ + search = capwap_hash_search_items(hash, hash->items[hashvalue], key); + if (!search) { + return; + } + + /* */ + capwap_hash_deleteitem(hash, key, search, hashvalue); +} + /* */ void capwap_hash_deleteall(struct capwap_hash* hash) { unsigned long i; @@ -482,27 +497,6 @@ void capwap_hash_deleteall(struct capwap_hash* hash) { hash->count = 0; } -/* */ -int capwap_hash_hasitem(struct capwap_hash* hash, const void* key) { - unsigned long hashvalue; - struct capwap_hash_item* items; - struct capwap_hash_item* result; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - - /* Search item */ - hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); - items = hash->items[hashvalue]; - if (!items) { - return 0; - } - - /* */ - result = capwap_hash_search_items(hash, items, key); - return (result ? 1 : 0); -} - /* */ void* capwap_hash_search(struct capwap_hash* hash, const void* key) { unsigned long hashvalue; @@ -513,7 +507,7 @@ void* capwap_hash_search(struct capwap_hash* hash, const void* key) { ASSERT(key != NULL); /* Search item */ - hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); + hashvalue = hash->item_gethash(key, hash->hashsize); items = hash->items[hashvalue]; if (!items) { return NULL; @@ -530,14 +524,32 @@ void* capwap_hash_search(struct capwap_hash* hash, const void* key) { /* */ void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param) { + int result; unsigned long i; ASSERT(hash != NULL); ASSERT(item_foreach != NULL); + /* */ + hash->removeitems = NULL; + + /* */ for (i = 0; i < hash->hashsize; i++) { if (hash->items[i]) { - capwap_hash_foreach_items(hash, hash->items[i], item_foreach, param); + result = capwap_hash_foreach_items(hash, hash->items[i], item_foreach, param); + if (result == HASH_BREAK) { + break; + } } } + + /* Delete marked items */ + while (hash->removeitems) { + struct capwap_hash_item* item = hash->removeitems; + const void* key = hash->item_getkey(item->data); + + /* */ + hash->removeitems = item->removenext; + capwap_hash_deleteitem(hash, key, item, hash->item_gethash(key, hash->hashsize)); + } } diff --git a/src/common/capwap_hash.h b/src/common/capwap_hash.h index 7e556a6..9e6940e 100644 --- a/src/common/capwap_hash.h +++ b/src/common/capwap_hash.h @@ -1,14 +1,18 @@ #ifndef __CAPWAP_HASH_HEADER__ #define __CAPWAP_HASH_HEADER__ -typedef unsigned long (*capwap_hash_item_gethash)(const void* key, unsigned long keysize, unsigned long hashsize); -typedef int (*capwap_hash_item_cmp)(const void* key1, const void* key2, unsigned long keysize); -typedef void (*capwap_hash_item_free)(const void* key, unsigned long keysize, void* data); +typedef unsigned long (*capwap_hash_item_gethash)(const void* key, unsigned long hashsize); +typedef const void* (*capwap_hash_item_getkey)(const void* data); +typedef int (*capwap_hash_item_cmp)(const void* key1, const void* key2); +typedef void (*capwap_hash_item_free)(void* data); -typedef int (*capwap_hash_item_foreach)(const void* key, unsigned long keysize, void* data, void* param); +#define HASH_BREAK 0 +#define HASH_CONTINUE 1 +#define HASH_DELETE_AND_BREAK 2 +#define HASH_DELETE_AND_CONTINUE 3 +typedef int (*capwap_hash_item_foreach)(void* data, void* param); struct capwap_hash_item { - void* key; void* data; int height; @@ -16,30 +20,34 @@ struct capwap_hash_item { struct capwap_hash_item* parent; struct capwap_hash_item* left; struct capwap_hash_item* right; + + struct capwap_hash_item* removenext; }; struct capwap_hash { struct capwap_hash_item** items; unsigned long hashsize; - unsigned long keysize; /* */ unsigned long count; + /* */ + struct capwap_hash_item* removeitems; + /* Callback functions */ - capwap_hash_item_gethash item_hash; + capwap_hash_item_gethash item_gethash; + capwap_hash_item_getkey item_getkey; capwap_hash_item_cmp item_cmp; capwap_hash_item_free item_free; }; -struct capwap_hash* capwap_hash_create(unsigned long hashsize, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free); +struct capwap_hash* capwap_hash_create(unsigned long hashsize); void capwap_hash_free(struct capwap_hash* hash); -void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data); +void capwap_hash_add(struct capwap_hash* hash, void* data); void capwap_hash_delete(struct capwap_hash* hash, const void* key); void capwap_hash_deleteall(struct capwap_hash* hash); -int capwap_hash_hasitem(struct capwap_hash* hash, const void* key); void* capwap_hash_search(struct capwap_hash* hash, const void* key); void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param); diff --git a/src/common/capwap_rwlock.c b/src/common/capwap_rwlock.c index 2d8c2ec..2af9e8e 100644 --- a/src/common/capwap_rwlock.c +++ b/src/common/capwap_rwlock.c @@ -38,7 +38,7 @@ void capwap_rwlock_wrlock(capwap_rwlock_t* lock) { } /* */ -void capwap_rwlock_exit(capwap_rwlock_t* lock) { +void capwap_rwlock_unlock(capwap_rwlock_t* lock) { ASSERT(lock != NULL); pthread_rwlock_unlock(&lock->rwlock); diff --git a/src/common/capwap_rwlock.h b/src/common/capwap_rwlock.h index 5b626b1..df0dde9 100644 --- a/src/common/capwap_rwlock.h +++ b/src/common/capwap_rwlock.h @@ -13,7 +13,7 @@ int capwap_rwlock_init(capwap_rwlock_t* lock); void capwap_rwlock_destroy(capwap_rwlock_t* lock); void capwap_rwlock_rdlock(capwap_rwlock_t* lock); void capwap_rwlock_wrlock(capwap_rwlock_t* lock); -void capwap_rwlock_exit(capwap_rwlock_t* lock); +void capwap_rwlock_unlock(capwap_rwlock_t* lock); #endif /* CAPWAP_MULTITHREADING_ENABLE */ diff --git a/src/common/capwap_timeout.c b/src/common/capwap_timeout.c index f1ab3ad..4f2774e 100644 --- a/src/common/capwap_timeout.c +++ b/src/common/capwap_timeout.c @@ -7,12 +7,17 @@ /* #define CAPWAP_TIMEOUT_LOGGING_DEBUG 1 */ /* */ -static unsigned long capwap_timeout_hash_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { - return (*(unsigned long*)key % hashsize); +static unsigned long capwap_timeout_hash_item_gethash(const void* key, unsigned long hashsize) { + return (*((unsigned long*)key) % hashsize); } /* */ -static int capwap_timeout_hash_item_cmp(const void* key1, const void* key2, unsigned long keysize) { +static const void* capwap_timeout_hash_item_getkey(const void* data) { + return (const void*)&((struct capwap_timeout_item*)((struct capwap_list_item*)data)->item)->index; +} + +/* */ +static int capwap_timeout_hash_item_cmp(const void* key1, const void* key2) { unsigned long value1 = *(unsigned long*)key1; unsigned long value2 = *(unsigned long*)key2; @@ -101,7 +106,11 @@ struct capwap_timeout* capwap_timeout_init(void) { memset(timeout, 0, sizeof(struct capwap_timeout)); /* */ - timeout->itemsreference = capwap_hash_create(CAPWAP_TIMEOUT_HASH_COUNT, sizeof(unsigned long), capwap_timeout_hash_item_gethash, capwap_timeout_hash_item_cmp, NULL); + timeout->itemsreference = capwap_hash_create(CAPWAP_TIMEOUT_HASH_COUNT); + timeout->itemsreference->item_gethash = capwap_timeout_hash_item_gethash; + timeout->itemsreference->item_getkey = capwap_timeout_hash_item_getkey; + timeout->itemsreference->item_cmp = capwap_timeout_hash_item_cmp; + timeout->itemstimeout = capwap_list_create(); return timeout; @@ -204,7 +213,7 @@ unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long i #endif /* Add itemlist into hash for rapid searching */ - capwap_hash_add(timeout->itemsreference, (const void*)&item->index, (void*)itemlist); + capwap_hash_add(timeout->itemsreference, (void*)itemlist); /* Add itemlist into order list */ capwap_timeout_additem(timeout->itemstimeout, itemlist); diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index 3a54ad6..397eaf4 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -19,7 +19,6 @@ static struct wifi_driver_instance wifi_driver[] = { /* */ #define WIFI_STATIONS_HASH_SIZE 256 -#define WIFI_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH /* Wifi Manager */ static struct wifi_global g_wifiglobal; @@ -131,16 +130,24 @@ static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int r } /* */ -static unsigned long wifi_hash_station_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { +static unsigned long wifi_hash_station_gethash(const void* key, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; - ASSERT(keysize == MACADDRESS_EUI48_LENGTH); - return ((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]); } /* */ -static void wifi_hash_station_free(const void* key, unsigned long keysize, void* data) { +static const void* wifi_hash_station_getkey(const void* data) { + return (const void*)((struct wifi_station*)data)->address; +} + +/* */ +static int wifi_hash_station_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + +/* */ +static void wifi_hash_station_free(void* data) { struct wifi_station* station = (struct wifi_station*)data; ASSERT(data != NULL); @@ -284,7 +291,7 @@ static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const ui station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; /* Add to pool */ - capwap_hash_add(g_wifiglobal.stations, address, station); + capwap_hash_add(g_wifiglobal.stations, station); } /* Set station to WLAN */ @@ -1103,7 +1110,11 @@ int wifi_driver_init(struct capwap_timeout* timeout) { /* */ g_wifiglobal.timeout = timeout; g_wifiglobal.devices = capwap_list_create(); - g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE, WIFI_STATIONS_KEY_SIZE, wifi_hash_station_gethash, NULL, wifi_hash_station_free); + g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE); + g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash; + g_wifiglobal.stations->item_getkey = wifi_hash_station_getkey; + g_wifiglobal.stations->item_cmp = wifi_hash_station_cmp; + g_wifiglobal.stations->item_free = wifi_hash_station_free; return 0; } diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index bbac664..91c1dfc 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -52,20 +52,32 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { } /* */ -static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { +static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; - ASSERT(keysize == ETH_ALEN); - return (((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]) >> 2); } +/* */ +static const void* wtp_radio_acl_item_getkey(const void* data) { + return NULL; // TODO +} + +/* */ +static int wtp_radio_acl_item_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + + /* */ void wtp_radio_init(void) { g_wtp.radios = capwap_array_create(sizeof(struct wtp_radio), 0, 1); g_wtp.defaultaclstations = WTP_RADIO_ACL_STATION_ALLOW; - g_wtp.aclstations = capwap_hash_create(WTP_RADIO_ACL_HASH_SIZE, WTP_RADIO_ACL_KEY_SIZE, wtp_radio_acl_item_gethash, NULL, NULL); + g_wtp.aclstations = capwap_hash_create(WTP_RADIO_ACL_HASH_SIZE); + g_wtp.aclstations->item_gethash = wtp_radio_acl_item_gethash; + g_wtp.aclstations->item_getkey = wtp_radio_acl_item_getkey; + g_wtp.aclstations->item_cmp = wtp_radio_acl_item_cmp; } /* */ @@ -755,7 +767,7 @@ int wtp_radio_acl_station(const uint8_t* macaddress) { ASSERT(macaddress != NULL); /* Check if exist ACL for station */ - if (capwap_hash_hasitem(g_wtp.aclstations, macaddress)) { + if (capwap_hash_search(g_wtp.aclstations, macaddress)) { return ((g_wtp.defaultaclstations == WTP_RADIO_ACL_STATION_ALLOW) ? WTP_RADIO_ACL_STATION_DENY : WTP_RADIO_ACL_STATION_ALLOW); } @@ -767,11 +779,11 @@ int wtp_radio_acl_station(const uint8_t* macaddress) { void wtp_radio_acl_addstation(const uint8_t* macaddress) { ASSERT(macaddress != NULL); - capwap_hash_add(g_wtp.aclstations, macaddress, NULL); + // TODO capwap_hash_add(g_wtp.aclstations, macaddress, NULL); } void wtp_radio_acl_deletestation(const uint8_t* macaddress) { ASSERT(macaddress != NULL); - capwap_hash_delete(g_wtp.aclstations, macaddress); + // TODO capwap_hash_delete(g_wtp.aclstations, macaddress); } diff --git a/src/wtp/wtp_radio.h b/src/wtp/wtp_radio.h index bf15841..87799fa 100644 --- a/src/wtp/wtp_radio.h +++ b/src/wtp/wtp_radio.h @@ -11,7 +11,6 @@ /* */ #define WTP_RADIO_ACL_HASH_SIZE 64 -#define WTP_RADIO_ACL_KEY_SIZE ETH_ALEN #define WTP_RADIO_ACL_STATION_ALLOW 0 #define WTP_RADIO_ACL_STATION_DENY 1 diff --git a/webservice/smartcapwap.wsdl b/webservice/smartcapwap.wsdl index 203833f..6eafbab 100644 --- a/webservice/smartcapwap.wsdl +++ b/webservice/smartcapwap.wsdl @@ -85,6 +85,20 @@ + + + + + + + + + + + + + + @@ -134,6 +148,10 @@ + + + + @@ -141,6 +159,12 @@ + + + + + + @@ -248,11 +272,32 @@ + + + + + + + + + - + + + + + + + + + + + + + @@ -274,5 +319,8 @@ + + +