257 lines
7.7 KiB
C
257 lines
7.7 KiB
C
#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;
|
|
union sockaddr_capwap sender;
|
|
char data[0];
|
|
};
|
|
|
|
static struct ac_discovery_t g_ac_discovery;
|
|
|
|
/* */
|
|
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender) {
|
|
struct capwap_list_item* item;
|
|
struct ac_discovery_packet* packet;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(buffersize > 0);
|
|
ASSERT(sock >= 0);
|
|
ASSERT(sender != NULL);
|
|
|
|
/* TODO: mettere un history delle discovery request già 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(union sockaddr_capwap));
|
|
memcpy(packet->data, buffer, buffersize);
|
|
|
|
/* Append to packets list */
|
|
capwap_lock_enter(&g_ac_discovery.packetslock);
|
|
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
|
|
capwap_event_signal(&g_ac_discovery.waitpacket);
|
|
capwap_lock_exit(&g_ac_discovery.packetslock);
|
|
}
|
|
|
|
/* */
|
|
static struct capwap_packet_txmng* ac_create_discovery_response(struct capwap_parsed_packet* packet) {
|
|
int i;
|
|
unsigned short binding;
|
|
struct capwap_list* controllist;
|
|
struct capwap_list_item* item;
|
|
struct capwap_header_data capwapheader;
|
|
struct capwap_packet_txmng* txmngpacket;
|
|
|
|
/* Check is valid binding */
|
|
binding = GET_WBID_HEADER(packet->rxmngpacket->header);
|
|
if (!ac_valid_binding(binding)) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Update statistics */
|
|
ac_update_statistics();
|
|
|
|
/* Build packet */
|
|
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, binding);
|
|
txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, CAPWAP_DISCOVERY_RESPONSE, packet->rxmngpacket->ctrlmsg.seq, g_ac.mtu);
|
|
|
|
/* Prepare discovery response */
|
|
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ACDESCRIPTION, &g_ac.descriptor);
|
|
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ACNAME, &g_ac.acname);
|
|
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
|
|
struct capwap_array* wtpradioinformation = (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION);
|
|
|
|
for (i = 0; i < wtpradioinformation->count; i++) {
|
|
struct capwap_80211_wtpradioinformation_element* radio;
|
|
|
|
radio = *(struct capwap_80211_wtpradioinformation_element**)capwap_array_get_item_pointer(wtpradioinformation, i);
|
|
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, radio);
|
|
}
|
|
}
|
|
|
|
/* 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.ss_family == AF_INET) {
|
|
struct capwap_controlipv4_element element;
|
|
|
|
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
|
|
element.wtpcount = sessioncontrol->count;
|
|
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element);
|
|
} else if (sessioncontrol->localaddress.ss.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_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV6, &element);
|
|
}
|
|
}
|
|
|
|
capwap_list_free(controllist);
|
|
|
|
/* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */
|
|
|
|
return txmngpacket;
|
|
}
|
|
|
|
/* 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 ac_discovery_packet* acpacket;
|
|
struct capwap_parsed_packet packet;
|
|
struct capwap_packet_rxmng* rxmngpacket;
|
|
|
|
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;
|
|
}
|
|
|
|
/* */
|
|
acpacket = (struct ac_discovery_packet*)itempacket->item;
|
|
sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet);
|
|
|
|
/* Accept only discovery request don't fragment */
|
|
rxmngpacket = capwap_packet_rxmng_create_message();
|
|
if (capwap_packet_rxmng_add_recv_packet(rxmngpacket, acpacket->data, sizedata) == CAPWAP_RECEIVE_COMPLETE_PACKET) {
|
|
/* Validate message */
|
|
if (capwap_check_message_type(rxmngpacket) == VALID_MESSAGE_TYPE) {
|
|
/* Parsing packet */
|
|
if (capwap_parsing_packet(rxmngpacket, &packet) == PARSING_COMPLETE) {
|
|
/* Validate packet */
|
|
if (!capwap_validate_parsed_packet(&packet, NULL)) {
|
|
struct capwap_packet_txmng* txmngpacket;
|
|
|
|
/* */
|
|
log_printf(LOG_DEBUG, "Receive discovery request packet");
|
|
|
|
/* Creare discovery response */
|
|
txmngpacket = ac_create_discovery_response(&packet);
|
|
if (txmngpacket) {
|
|
struct capwap_list* responsefragmentpacket;
|
|
|
|
/* Discovery response complete, get fragment packets */
|
|
responsefragmentpacket = capwap_list_create();
|
|
capwap_packet_txmng_get_fragment_packets(txmngpacket, responsefragmentpacket, g_ac_discovery.fragmentid);
|
|
if (responsefragmentpacket->count > 1) {
|
|
g_ac_discovery.fragmentid++;
|
|
}
|
|
|
|
/* Free packets manager */
|
|
capwap_packet_txmng_free(txmngpacket);
|
|
|
|
/* Send discovery response to WTP */
|
|
if (!capwap_sendto_fragmentpacket(acpacket->sendsock, responsefragmentpacket, &acpacket->sender)) {
|
|
log_printf(LOG_DEBUG, "Warning: error to send discovery response packet");
|
|
}
|
|
|
|
/* Don't buffering a packets sent */
|
|
capwap_list_free(responsefragmentpacket);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Free resource */
|
|
capwap_free_parsed_packet(&packet);
|
|
}
|
|
}
|
|
|
|
/* Free resource */
|
|
capwap_packet_rxmng_free(rxmngpacket);
|
|
|
|
/* Free packet */
|
|
capwap_itemlist_free(itempacket);
|
|
}
|
|
}
|
|
|
|
/* */
|
|
static void* ac_discovery_thread(void* param) {
|
|
|
|
log_printf(LOG_DEBUG, "Discovery start");
|
|
ac_discovery_run();
|
|
log_printf(LOG_DEBUG, "Discovery stop");
|
|
|
|
/* Thread exit */
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
/* */
|
|
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) {
|
|
log_printf(LOG_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_destroy(&g_ac_discovery.packetslock);
|
|
capwap_list_free(g_ac_discovery.packets);
|
|
}
|