First commit
This commit is contained in:
276
src/ac/ac_discovery.c
Normal file
276
src/ac/ac_discovery.c
Normal file
@ -0,0 +1,276 @@
|
||||
#include "ac.h"
|
||||
#include "capwap_protocol.h"
|
||||
#include "ac_discovery.h"
|
||||
#include "ac_session.h"
|
||||
|
||||
#define AC_DISCOVERY_CLEANUP_TIMEOUT 1000
|
||||
|
||||
struct ac_discovery_t {
|
||||
pthread_t threadid;
|
||||
int endthread;
|
||||
|
||||
unsigned short fragmentid;
|
||||
unsigned char txseqnumber;
|
||||
|
||||
capwap_event_t waitpacket;
|
||||
capwap_lock_t packetslock;
|
||||
struct capwap_list* packets;
|
||||
};
|
||||
|
||||
struct ac_discovery_packet {
|
||||
int sendsock;
|
||||
struct sockaddr_storage sender;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
static struct ac_discovery_t g_ac_discovery;
|
||||
|
||||
/* */
|
||||
int ac_discovery_start(void) {
|
||||
int result;
|
||||
|
||||
memset(&g_ac_discovery, 0, sizeof(struct ac_discovery_t));
|
||||
|
||||
/* Init */
|
||||
capwap_event_init(&g_ac_discovery.waitpacket);
|
||||
capwap_lock_init(&g_ac_discovery.packetslock);
|
||||
g_ac_discovery.packets = capwap_list_create();
|
||||
|
||||
/* Create thread */
|
||||
result = pthread_create(&g_ac_discovery.threadid, NULL, ac_discovery_thread, NULL);
|
||||
if (result) {
|
||||
capwap_logging_debug("Unable create discovery thread");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
void ac_discovery_stop(void) {
|
||||
void* dummy;
|
||||
|
||||
g_ac_discovery.endthread = 1;
|
||||
capwap_event_signal(&g_ac_discovery.waitpacket);
|
||||
pthread_join(g_ac_discovery.threadid, &dummy);
|
||||
|
||||
/* Free memory */
|
||||
capwap_event_destroy(&g_ac_discovery.waitpacket);
|
||||
capwap_lock_exit(&g_ac_discovery.packetslock);
|
||||
capwap_list_free(g_ac_discovery.packets);
|
||||
}
|
||||
|
||||
/* */
|
||||
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender) {
|
||||
struct capwap_list_item* item;
|
||||
struct ac_discovery_packet* packet;
|
||||
|
||||
ASSERT(buffer != NULL);
|
||||
ASSERT(buffersize > 0);
|
||||
ASSERT(sock >= 0);
|
||||
ASSERT(sender != NULL);
|
||||
|
||||
/* TODO: mettere un history delle discovery request gi<67> processate per non eseguirle di nuovo */
|
||||
/* L'elemento deve rimanere per la durata minima di una discovery request */
|
||||
|
||||
/* Copy packet */
|
||||
item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize);
|
||||
packet = (struct ac_discovery_packet*)item->item;
|
||||
packet->sendsock = sock;
|
||||
memcpy(&packet->sender, sender, sizeof(struct sockaddr_storage));
|
||||
memcpy(packet->data, buffer, buffersize);
|
||||
|
||||
/* Append to packets list */
|
||||
capwap_lock_enter(&g_ac_discovery.packetslock);
|
||||
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
|
||||
capwap_event_signal(&g_ac_discovery.waitpacket);
|
||||
capwap_lock_exit(&g_ac_discovery.packetslock);
|
||||
}
|
||||
|
||||
/* */
|
||||
static struct capwap_build_packet* ac_create_discovery_response(struct capwap_build_packet* packet, struct capwap_element_discovery_request* discoveryrequest, struct sockaddr_storage* sender) {
|
||||
int i;
|
||||
unsigned short binding;
|
||||
struct capwap_list* controllist;
|
||||
struct capwap_list_item* item;
|
||||
struct capwap_build_packet* responsepacket;
|
||||
|
||||
ASSERT(packet != NULL);
|
||||
ASSERT(discoveryrequest != NULL);
|
||||
ASSERT(sender != NULL);
|
||||
|
||||
/* Check is valid binding */
|
||||
binding = GET_WBID_HEADER(&packet->header);
|
||||
if (!ac_valid_binding(binding)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Build packet */
|
||||
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
|
||||
responsepacket->isctrlmsg = 1;
|
||||
|
||||
/* Update statistics */
|
||||
ac_update_statistics();
|
||||
|
||||
/* Prepare discovery response */
|
||||
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_DISCOVERY_RESPONSE, packet->ctrlmsg.seq);
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACDESCRIPTOR_ELEMENT(&g_ac.descriptor));
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACNAME_ELEMENT(&g_ac.acname));
|
||||
|
||||
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
||||
for (i = 0; i < discoveryrequest->binding.ieee80211.wtpradioinformation->count; i++) {
|
||||
struct capwap_80211_wtpradioinformation_element* radio;
|
||||
|
||||
radio = (struct capwap_80211_wtpradioinformation_element*)capwap_array_get_item_pointer(discoveryrequest->binding.ieee80211.wtpradioinformation, i);
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(radio));
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Unknown capwap binding");
|
||||
}
|
||||
|
||||
/* Get information from any local address */
|
||||
controllist = capwap_list_create();
|
||||
ac_get_control_information(controllist);
|
||||
|
||||
for (item = controllist->first; item != NULL; item = item->next) {
|
||||
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
|
||||
|
||||
if (sessioncontrol->localaddress.ss_family == AF_INET) {
|
||||
struct capwap_controlipv4_element element;
|
||||
|
||||
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
|
||||
element.wtpcount = sessioncontrol->count;
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV4_ELEMENT(&element));
|
||||
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) {
|
||||
struct capwap_controlipv6_element element;
|
||||
|
||||
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
|
||||
element.wtpcount = sessioncontrol->count;
|
||||
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV6_ELEMENT(&element));
|
||||
}
|
||||
}
|
||||
|
||||
capwap_list_free(controllist);
|
||||
|
||||
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||||
|
||||
return responsepacket;
|
||||
}
|
||||
|
||||
/* Cleanup info discovery */
|
||||
static void ac_discovery_cleanup(void) {
|
||||
/* Clean history discovery request */
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* */
|
||||
static void ac_discovery_run(void) {
|
||||
int sizedata;
|
||||
struct capwap_list_item* itempacket;
|
||||
struct capwap_build_packet* buildpacket;
|
||||
struct ac_discovery_packet* packet;
|
||||
unsigned short binding;
|
||||
|
||||
while (!g_ac_discovery.endthread) {
|
||||
/* Get packet */
|
||||
capwap_lock_enter(&g_ac_discovery.packetslock);
|
||||
|
||||
itempacket = NULL;
|
||||
if (g_ac_discovery.packets->count > 0) {
|
||||
itempacket = capwap_itemlist_remove_head(g_ac_discovery.packets);
|
||||
}
|
||||
|
||||
capwap_lock_exit(&g_ac_discovery.packetslock);
|
||||
|
||||
if (!itempacket) {
|
||||
/* Wait packet with timeout*/
|
||||
if (!capwap_event_wait_timeout(&g_ac_discovery.waitpacket, AC_DISCOVERY_CLEANUP_TIMEOUT)) {
|
||||
ac_discovery_cleanup();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* */
|
||||
packet = (struct ac_discovery_packet*)itempacket->item;
|
||||
sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet);
|
||||
|
||||
/* Parsing packet */
|
||||
buildpacket = capwap_rx_packet_create(packet->data, sizedata, 1);
|
||||
if (buildpacket) {
|
||||
if (!capwap_build_packet_validate(buildpacket, NULL)) {
|
||||
struct capwap_element_discovery_request discoveryrequest;
|
||||
|
||||
/* */
|
||||
binding = GET_WBID_HEADER(&buildpacket->header);
|
||||
capwap_init_element_discovery_request(&discoveryrequest, binding);
|
||||
|
||||
/* Parsing elements list */
|
||||
if (capwap_parsing_element_discovery_request(&discoveryrequest, buildpacket->elementslist->first)) {
|
||||
struct capwap_build_packet* txpacket;
|
||||
capwap_fragment_packet_array* responsefragmentpacket = NULL;
|
||||
|
||||
/* Creare discovery response */
|
||||
txpacket = ac_create_discovery_response(buildpacket, &discoveryrequest, &packet->sender);
|
||||
if (txpacket) {
|
||||
int result = -1;
|
||||
|
||||
if (!capwap_build_packet_validate(txpacket, NULL)) {
|
||||
responsefragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
|
||||
result = capwap_fragment_build_packet(txpacket, responsefragmentpacket, g_ac.mtu, g_ac_discovery.fragmentid);
|
||||
if (result == 1) {
|
||||
g_ac_discovery.fragmentid++;
|
||||
}
|
||||
} else {
|
||||
capwap_logging_debug("Warning: build invalid discovery response packet");
|
||||
}
|
||||
|
||||
capwap_build_packet_free(txpacket);
|
||||
|
||||
/* Send discovery response to WTP */
|
||||
if (result >= 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < responsefragmentpacket->count; i++) {
|
||||
struct capwap_packet* sendpacket = (struct capwap_packet*)capwap_array_get_item_pointer(responsefragmentpacket, i);
|
||||
ASSERT(sendpacket != NULL);
|
||||
|
||||
if (!capwap_sendto(packet->sendsock, sendpacket->header, sendpacket->packetsize, NULL, &packet->sender)) {
|
||||
capwap_logging_debug("Warning: error to send discovery response packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't buffering a packets sent */
|
||||
if (responsefragmentpacket) {
|
||||
capwap_fragment_free(responsefragmentpacket);
|
||||
capwap_array_free(responsefragmentpacket);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free discovery request */
|
||||
capwap_free_element_discovery_request(&discoveryrequest, binding);
|
||||
}
|
||||
|
||||
/* */
|
||||
capwap_build_packet_free(buildpacket);
|
||||
}
|
||||
|
||||
/* Free packet */
|
||||
capwap_itemlist_free(itempacket);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
void* ac_discovery_thread(void* param) {
|
||||
|
||||
capwap_logging_debug("Discovery start");
|
||||
ac_discovery_run();
|
||||
capwap_logging_debug("Discovery stop");
|
||||
|
||||
/* Thread exit */
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
Reference in New Issue
Block a user