273 lines
11 KiB
C
273 lines
11 KiB
C
|
#include "ac.h"
|
||
|
#include "capwap_dfa.h"
|
||
|
#include "capwap_array.h"
|
||
|
#include "ac_session.h"
|
||
|
|
||
|
/* */
|
||
|
int ac_dfa_state_join(struct ac_session_t* session, struct capwap_packet* packet) {
|
||
|
int i;
|
||
|
int status = AC_DFA_ACCEPT_PACKET;
|
||
|
struct capwap_resultcode_element resultcode = { CAPWAP_RESULTCODE_FAILURE };
|
||
|
struct capwap_build_packet* responsepacket;
|
||
|
|
||
|
ASSERT(session != NULL);
|
||
|
|
||
|
if (packet) {
|
||
|
struct capwap_build_packet* buildpacket;
|
||
|
|
||
|
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
|
||
|
if (buildpacket) {
|
||
|
int validpacket;
|
||
|
unsigned long checkpacket;
|
||
|
struct capwap_array* returnedmessagearray = NULL;
|
||
|
capwap_unrecognized_element_array* unrecognizedarray;
|
||
|
struct capwap_element_join_request joinrequest;
|
||
|
unsigned short binding = GET_WBID_HEADER(&buildpacket->header);
|
||
|
|
||
|
/* */
|
||
|
unrecognizedarray = capwap_array_create(sizeof(struct unrecognized_info), 0);
|
||
|
|
||
|
/* */
|
||
|
checkpacket = capwap_build_packet_validate(buildpacket, unrecognizedarray);
|
||
|
if (!checkpacket) {
|
||
|
if (ac_valid_binding(binding)) {
|
||
|
if (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_JOIN_REQUEST) {
|
||
|
resultcode.code = CAPWAP_RESULTCODE_SUCCESS;
|
||
|
} else {
|
||
|
resultcode.code = CAPWAP_RESULTCODE_MSG_UNEXPECTED_INVALID_CURRENT_STATE;
|
||
|
}
|
||
|
} else {
|
||
|
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_BINDING_NOT_SUPPORTED;
|
||
|
}
|
||
|
} else {
|
||
|
if ((checkpacket & CAPWAP_MISSING_MANDATORY_MSG_ELEMENT) != 0) {
|
||
|
resultcode.code = CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT;
|
||
|
} else if ((checkpacket & CAPWAP_UNRECOGNIZED_MSG_ELEMENT) != 0) {
|
||
|
struct capwap_list_item* itemelement;
|
||
|
|
||
|
resultcode.code = CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT;
|
||
|
returnedmessagearray = capwap_array_create(sizeof(struct capwap_returnedmessage_element), unrecognizedarray->count);
|
||
|
|
||
|
for (i = 0; i < unrecognizedarray->count; i++) {
|
||
|
struct unrecognized_info* reasoninfo = capwap_array_get_item_pointer(unrecognizedarray, i);
|
||
|
|
||
|
/* Search element */
|
||
|
itemelement = buildpacket->elementslist->first;
|
||
|
while (itemelement != NULL) {
|
||
|
struct capwap_message_element* elementitem = (struct capwap_message_element*)itemelement->item;
|
||
|
|
||
|
if (ntohs(elementitem->type) == reasoninfo->element) {
|
||
|
struct capwap_returnedmessage_element* returnedelement = capwap_array_get_item_pointer(returnedmessagearray, i);
|
||
|
unsigned short length = sizeof(struct capwap_message_element) + ntohs(elementitem->length);
|
||
|
|
||
|
returnedelement->reason = reasoninfo->reason;
|
||
|
returnedelement->length = min(length, CAPWAP_RETURNED_MESSAGE_MAX_LENGTH);
|
||
|
memcpy(&returnedelement->message[0], elementitem, returnedelement->length);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Next */
|
||
|
itemelement = itemelement->next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* */
|
||
|
capwap_array_free(unrecognizedarray);
|
||
|
|
||
|
/* */
|
||
|
capwap_init_element_join_request(&joinrequest, binding);
|
||
|
if (resultcode.code == CAPWAP_RESULTCODE_SUCCESS) {
|
||
|
/* Parsing elements list */
|
||
|
if (capwap_parsing_element_join_request(&joinrequest, buildpacket->elementslist->first)) {
|
||
|
/* TODO: gestione richiesta */
|
||
|
|
||
|
/* Get sessionid */
|
||
|
memcpy(&session->sessionid, joinrequest.sessionid, sizeof(struct capwap_sessionid_element));
|
||
|
|
||
|
/* Get binding */
|
||
|
session->binding = binding;
|
||
|
|
||
|
resultcode.code = CAPWAP_RESULTCODE_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Create response */
|
||
|
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
|
||
|
responsepacket->isctrlmsg = 1;
|
||
|
|
||
|
/* Prepare join response */
|
||
|
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_JOIN_RESPONSE, buildpacket->ctrlmsg.seq);
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_RESULTCODE_ELEMENT(&resultcode));
|
||
|
|
||
|
/* Check is valid packet after parsing request */
|
||
|
validpacket = (((resultcode.code == CAPWAP_RESULTCODE_SUCCESS) || (resultcode.code == CAPWAP_RESULTCODE_SUCCESS_NAT_DETECTED)) ? 1 : 0);
|
||
|
if (validpacket) {
|
||
|
struct capwap_list* controllist;
|
||
|
struct capwap_list_item* item;
|
||
|
|
||
|
/* Update statistics */
|
||
|
ac_update_statistics();
|
||
|
|
||
|
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 < joinrequest.binding.ieee80211.wtpradioinformation->count; i++) {
|
||
|
struct capwap_80211_wtpradioinformation_element* radio;
|
||
|
|
||
|
radio = (struct capwap_80211_wtpradioinformation_element*)capwap_array_get_item_pointer(joinrequest.binding.ieee80211.wtpradioinformation, i);
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(radio));
|
||
|
}
|
||
|
} else {
|
||
|
capwap_logging_debug("Unknown capwap binding");
|
||
|
}
|
||
|
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ECNSUPPORT_ELEMENT(&session->dfa.ecn));
|
||
|
|
||
|
/* 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);
|
||
|
|
||
|
if (session->acctrladdress.ss_family == AF_INET) {
|
||
|
struct capwap_localipv4_element addr;
|
||
|
|
||
|
memcpy(&addr.address, &((struct sockaddr_in*)&session->acctrladdress)->sin_addr, sizeof(struct in_addr));
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_LOCALIPV4_ELEMENT(&addr));
|
||
|
} else if (session->acctrladdress.ss_family == AF_INET6) {
|
||
|
struct capwap_localipv6_element addr;
|
||
|
|
||
|
memcpy(&addr.address, &((struct sockaddr_in6*)&session->acctrladdress)->sin6_addr, sizeof(struct in6_addr));
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_LOCALIPV6_ELEMENT(&addr));
|
||
|
}
|
||
|
|
||
|
/* CAPWAP_CREATE_ACIPV4LIST_ELEMENT */ /* TODO */
|
||
|
/* CAPWAP_CREATE_ACIPV6LIST_ELEMENT */ /* TODO */
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_TRANSPORT_ELEMENT(&session->dfa.transport));
|
||
|
/* CAPWAP_CREATE_IMAGEIDENTIFIER_ELEMENT */ /* TODO */
|
||
|
/* CAPWAP_CREATE_MAXIMUMMESSAGELENGTH_ELEMENT */ /* TODO */
|
||
|
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
|
||
|
} else if (resultcode.code == CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT) {
|
||
|
ASSERT(returnedmessagearray != NULL);
|
||
|
|
||
|
for (i = 0; i < returnedmessagearray->count; i++) {
|
||
|
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_RETURNEDMESSAGE_ELEMENT(capwap_array_get_item_pointer(returnedmessagearray, i)));
|
||
|
}
|
||
|
|
||
|
capwap_array_free(returnedmessagearray);
|
||
|
}
|
||
|
|
||
|
/* Validate packet */
|
||
|
if (!validpacket || !capwap_build_packet_validate(responsepacket, NULL)) {
|
||
|
int result;
|
||
|
|
||
|
/* Free old reference for this request */
|
||
|
ac_free_reference_last_response(session);
|
||
|
|
||
|
/* Send join response to WTP */
|
||
|
result = capwap_fragment_build_packet(responsepacket, session->responsefragmentpacket, session->mtu, session->fragmentid);
|
||
|
if (result >= 0) {
|
||
|
if (result == 1) {
|
||
|
session->fragmentid++;
|
||
|
}
|
||
|
|
||
|
/* Save remote sequence number */
|
||
|
session->remoteseqnumber = buildpacket->ctrlmsg.seq;
|
||
|
capwap_get_packet_digest((void*)packet->header, packet->packetsize, session->lastrecvpackethash);
|
||
|
|
||
|
/* Send */
|
||
|
for (i = 0; i < session->responsefragmentpacket->count; i++) {
|
||
|
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->responsefragmentpacket, i);
|
||
|
ASSERT(txpacket != NULL);
|
||
|
|
||
|
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
|
||
|
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
|
||
|
capwap_logging_debug("Warning: error to send join response packet");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
capwap_logging_debug("Warning: build invalid join response packet");
|
||
|
}
|
||
|
|
||
|
/* Free memory */
|
||
|
capwap_build_packet_free(responsepacket);
|
||
|
capwap_free_element_join_request(&joinrequest, binding);
|
||
|
capwap_build_packet_free(buildpacket);
|
||
|
|
||
|
/* Change state */
|
||
|
if (validpacket) {
|
||
|
ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE);
|
||
|
} else {
|
||
|
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||
|
status = AC_DFA_NO_PACKET;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/* Join timeout */
|
||
|
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||
|
status = AC_DFA_NO_PACKET;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* */
|
||
|
int ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_packet* packet) {
|
||
|
int status = AC_DFA_ACCEPT_PACKET;
|
||
|
|
||
|
ASSERT(session != NULL);
|
||
|
|
||
|
if (packet) {
|
||
|
unsigned short lengthpayload;
|
||
|
|
||
|
lengthpayload = packet->packetsize - GET_HLEN_HEADER(packet->header) * 4;
|
||
|
if (lengthpayload >= sizeof(struct capwap_control_message)) {
|
||
|
struct capwap_control_message* ctrlmsg = (struct capwap_control_message*)packet->payload;
|
||
|
unsigned long type = ntohl(ctrlmsg->type);
|
||
|
|
||
|
if (type == CAPWAP_CONFIGURATION_STATUS_REQUEST) {
|
||
|
ac_dfa_change_state(session, CAPWAP_CONFIGURE_STATE);
|
||
|
status = ac_dfa_state_configure(session, packet);
|
||
|
} else if (type == CAPWAP_IMAGE_DATA_REQUEST) {
|
||
|
ac_dfa_change_state(session, CAPWAP_IMAGE_DATA_STATE);
|
||
|
status = ac_dfa_state_imagedata(session, packet);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/* Join timeout */
|
||
|
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
|
||
|
status = AC_DFA_NO_PACKET;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* */
|
||
|
int ac_dfa_state_join_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
|
||
|
return ac_session_teardown_connection(session);
|
||
|
}
|