Improved the management of soap request/response.

The director has the opportunity to change the configuration of AC in join
connection. The virtual interfaces which encapsulate the wifi stations is
managed dynamically by the Director.
The AC must request authorization from Director for associate a station.
This commit is contained in:
vemax78 2014-10-19 21:37:22 +02:00
parent 63f5fcea19
commit 8937ded1d3
24 changed files with 1049 additions and 549 deletions

View File

@ -3,6 +3,7 @@
#include "ac_session.h"
#include "capwap_dtls.h"
#include "capwap_socket.h"
#include "ac_wlans.h"
#include <libconfig.h>
@ -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");

View File

@ -14,6 +14,7 @@
#include <pthread.h>
#include <linux/if_ether.h>
#include <json/json.h>
#include <ac_kmod.h>
@ -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;
};
};

View File

@ -3,7 +3,6 @@
#include "ac_backend.h"
#include "ac_soap.h"
#include "ac_session.h"
#include <json/json.h>
/* */
#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);

View File

@ -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));

View File

@ -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 */

View File

@ -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();

View File

@ -7,8 +7,151 @@
#include <signal.h>
#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();

View File

@ -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) {

View File

@ -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__ */

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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]));
}
/* */

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -85,6 +85,20 @@
<wsdl:part name="status" type="xs:int"/>
</wsdl:message>
<wsdl:message name="updateBackendEventResponse"/>
<wsdl:message name="getConfiguration">
<wsdl:part name="idsession" type="xs:string"/>
</wsdl:message>
<wsdl:message name="getConfigurationResponse">
<wsdl:part name="return" type="xs:base64Binary"/>
</wsdl:message>
<wsdl:message name="authorizeStation">
<wsdl:part name="idsession" type="xs:string"/>
<wsdl:part name="idwtp" type="xs:string"/>
<wsdl:part name="station" type="xs:base64Binary"/>
</wsdl:message>
<wsdl:message name="authorizeStationResponse">
<wsdl:part name="return" type="xs:base64Binary"/>
</wsdl:message>
<wsdl:portType name="Presence">
<wsdl:operation name="joinBackend">
<wsdl:input message="tns:joinBackend"/>
@ -134,6 +148,10 @@
<wsdl:input message="tns:checkWTPSession"/>
<wsdl:output message="tns:checkWTPSessionResponse"/>
</wsdl:operation>
<wsdl:operation name="authorizeStation">
<wsdl:input message="tns:authorizeStation"/>
<wsdl:output message="tns:authorizeStationResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="AccessControllerWTPConfiguration">
<wsdl:operation name="getWTPConfiguration">
@ -141,6 +159,12 @@
<wsdl:output message="tns:getWTPConfigurationResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="AccessController">
<wsdl:operation name="getConfiguration">
<wsdl:input message="tns:getConfiguration"/>
<wsdl:output message="tns:getConfigurationResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Presence" type="tns:Presence">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="joinBackend">
@ -248,11 +272,32 @@
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="authorizeStation">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="AccessControllerWTPConfiguration" type="tns:AccessControllerWTPConfiguration">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getWTPConfiguration">
<soap:operation soapAction="urn:#NewOperation"/>
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="AccessController" type="tns:AccessController">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getConfiguration">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
@ -274,5 +319,8 @@
<wsdl:port name="accesscontrollerwtpconfiguration" binding="tns:AccessControllerWTPConfiguration">
<soap:address location="http://localhost/"/>
</wsdl:port>
<wsdl:port name="accesscontroller" binding="tns:AccessController">
<soap:address location="http://localhost/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>