diff --git a/build/ac/Makefile.am b/build/ac/Makefile.am index c264ffd..7bbabab 100755 --- a/build/ac/Makefile.am +++ b/build/ac/Makefile.am @@ -50,6 +50,7 @@ ac_SOURCES = \ $(top_srcdir)/src/ac/ac_backend.c \ $(top_srcdir)/src/ac/ac_execute.c \ $(top_srcdir)/src/ac/ac_session.c \ + $(top_srcdir)/src/ac/ac_session_data.c \ $(top_srcdir)/src/ac/ac_discovery.c \ $(top_srcdir)/src/ac/ac_80211_json.c \ $(top_srcdir)/src/ac/ac_80211_json_addwlan.c \ diff --git a/src/ac/ac.c b/src/ac/ac.c index ac14c5e..d696456 100644 --- a/src/ac/ac.c +++ b/src/ac/ac.c @@ -66,9 +66,9 @@ 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); - g_ac.datasessionshandshake = capwap_list_create(); /* Backend */ g_ac.availablebackends = capwap_array_create(sizeof(struct ac_http_soap_server*), 0, 0); @@ -100,12 +100,12 @@ static void ac_destroy(void) { /* */ capwap_array_free(g_ac.dfa.acipv4list.addresses); capwap_array_free(g_ac.dfa.acipv6list.addresses); - + /* 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); - capwap_list_free(g_ac.datasessionshandshake); ac_session_msgqueue_free(); /* Backend */ diff --git a/src/ac/ac.h b/src/ac/ac.h index b4436ee..85a458f 100644 --- a/src/ac/ac.h +++ b/src/ac/ac.h @@ -74,14 +74,6 @@ struct ac_state { int rfcWaitDTLS; }; -/* Handshake DTLS Data Channel */ -struct ac_data_session_handshake { - struct capwap_socket socket; - struct sockaddr_storage acaddress; - struct sockaddr_storage wtpaddress; - struct capwap_dtls dtls; -}; - /* AC */ struct ac_t { int standalone; @@ -102,9 +94,9 @@ struct ac_t { /* Sessions */ struct capwap_list* sessions; + struct capwap_list* sessionsdata; struct capwap_list* sessionsthread; capwap_rwlock_t sessionslock; - struct capwap_list* datasessionshandshake; /* Dtls */ int enabledtls; diff --git a/src/ac/ac_dfa_configure.c b/src/ac/ac_dfa_configure.c index 52484cd..4796313 100644 --- a/src/ac/ac_dfa_configure.c +++ b/src/ac/ac_dfa_configure.c @@ -754,7 +754,7 @@ void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_p capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash); /* Send Configure response to WTP */ - if (!capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->responsefragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { /* Response is already created and saved. When receive a re-request, DFA autoresponse */ capwap_logging_debug("Warning: error to send configuration status response packet"); } diff --git a/src/ac/ac_dfa_datacheck.c b/src/ac/ac_dfa_datacheck.c index 31369e3..e167526 100644 --- a/src/ac/ac_dfa_datacheck.c +++ b/src/ac/ac_dfa_datacheck.c @@ -220,7 +220,7 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash); /* Send Change event response to WTP */ - if (!capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->responsefragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { /* Response is already created and saved. When receive a re-request, DFA autoresponse */ capwap_logging_debug("Warning: error to send change event response packet"); } @@ -240,69 +240,9 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p /* */ void ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_parsed_packet* packet) { - struct capwap_list* txfragpacket; - struct capwap_header_data capwapheader; - struct capwap_packet_txmng* txmngpacket; - struct ac_soap_response* response; - ASSERT(session != NULL); - - if (packet) { - /* Wait Data Channel Keep-Alive packet */ - if (!packet->rxmngpacket->isctrlpacket && IS_FLAG_K_HEADER(packet->rxmngpacket->header)) { - if (!memcmp(capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID), &session->sessionid, sizeof(struct capwap_sessionid_element))) { - int result = 0; - /* Build packet */ - capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(packet->rxmngpacket->header)); - capwap_header_set_keepalive_flag(&capwapheader, 1); - txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, session->mtu); - - /* Add message element */ - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &session->sessionid); - - /* Data keepalive complete, get fragment packets into local list */ - txfragpacket = capwap_list_create(); - capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0); - if (txfragpacket->count == 1) { - /* Send Data keepalive to WTP */ - if (capwap_crypt_sendto_fragmentpacket(&session->datadtls, session->datasocket.socket[session->datasocket.type], txfragpacket, &session->acdataaddress, &session->wtpdataaddress)) { - result = 1; - } else { - capwap_logging_debug("Warning: error to send data channel keepalive packet"); - } - } else { - capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet"); - } - - /* Free packets manager */ - capwap_list_free(txfragpacket); - capwap_packet_txmng_free(txmngpacket); - - /* Capwap handshake complete, notify event to backend */ - if (result) { - result = 0; - response = ac_soap_runningwtpsession(session, session->wtpid); - if (response) { - if (response->responsecode == HTTP_RESULT_OK) { - result = 1; - } - - ac_soapclient_free_response(response); - } - } - - /* */ - if (result) { - ac_dfa_change_state(session, CAPWAP_RUN_STATE); - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - } else { - ac_session_teardown(session); - } - } - } - } else { - /* Configure timeout */ - ac_session_teardown(session); + if (!packet) { + ac_session_teardown(session); /* Configure timeout */ } } diff --git a/src/ac/ac_dfa_dtls.c b/src/ac/ac_dfa_dtls.c index d1b9823..e63f675 100644 --- a/src/ac/ac_dfa_dtls.c +++ b/src/ac/ac_dfa_dtls.c @@ -4,13 +4,21 @@ #include "ac_session.h" /* DTLS BIO send */ -int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) { +static int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) { struct ac_session_t* session = (struct ac_session_t*)param; - struct capwap_socket* socket = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->ctrlsocket : &session->datasocket); - struct sockaddr_storage* wtpaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->wtpctrladdress : &session->wtpdataaddress); - struct sockaddr_storage* acaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->acctrladdress : &session->acdataaddress); - - return capwap_sendto(socket->socket[socket->type], buffer, length, acaddress, wtpaddress); + + ASSERT(dtls->session == CAPWAP_DTLS_CONTROL_SESSION); + + return capwap_sendto(session->connection.socket.socket[session->connection.socket.type], buffer, length, &session->connection.localaddr, &session->connection.remoteaddr); +} + +/* DTLS BIO Data send */ +static int ac_bio_data_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) { + struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param; + + ASSERT(dtls->session == CAPWAP_DTLS_DATA_SESSION); + + return capwap_sendto(sessiondata->connection.socket.socket[sessiondata->connection.socket.type], buffer, length, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr); } /* */ @@ -18,11 +26,11 @@ int ac_dtls_setup(struct ac_session_t* session) { ASSERT(session != NULL); /* Create DTLS session */ - if (!capwap_crypt_createsession(&session->ctrldtls, CAPWAP_DTLS_CONTROL_SESSION, &g_ac.dtlscontext, ac_bio_send, session)) { + if (!capwap_crypt_createsession(&session->dtls, CAPWAP_DTLS_CONTROL_SESSION, &g_ac.dtlscontext, ac_bio_send, session)) { return 0; } - if (capwap_crypt_open(&session->ctrldtls, &session->wtpctrladdress) == CAPWAP_HANDSHAKE_ERROR) { + if (capwap_crypt_open(&session->dtls, &session->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) { return 0; } @@ -31,3 +39,19 @@ int ac_dtls_setup(struct ac_session_t* session) { capwap_set_timeout(session->dfa.rfcWaitDTLS, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); return 1; } + +/* */ +int ac_dtls_data_setup(struct ac_session_data_t* sessiondata) { + ASSERT(sessiondata != NULL); + + /* Create DTLS session */ + if (!capwap_crypt_createsession(&sessiondata->dtls, CAPWAP_DTLS_DATA_SESSION, &g_ac.dtlscontext, ac_bio_data_send, sessiondata)) { + return 0; + } + + if (capwap_crypt_open(&sessiondata->dtls, &sessiondata->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) { + return 0; + } + + return 1; +} diff --git a/src/ac/ac_dfa_join.c b/src/ac/ac_dfa_join.c index c4087d0..23cb86c 100644 --- a/src/ac/ac_dfa_join.c +++ b/src/ac/ac_dfa_join.c @@ -282,7 +282,7 @@ static struct ac_soap_response* ac_dfa_state_join_parsing_request(struct ac_sess char ipbuffer[INET6_ADDRSTRLEN]; jsonhash = json_object_new_object(); - json_object_object_add(jsonhash, "Address", json_object_new_string(inet_ntop(AF_INET, (void*)&localipv6->address, ipbuffer, INET6_ADDRSTRLEN))); + json_object_object_add(jsonhash, "Address", json_object_new_string(inet_ntop(AF_INET6, (void*)&localipv6->address, ipbuffer, INET6_ADDRSTRLEN))); json_object_object_add(jsonparam, "CAPWAPLocalIPv6Address", jsonhash); } @@ -449,15 +449,15 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session, capwap_list_free(controllist); /* CAPWAP Local IP Address */ - if (session->acctrladdress.ss_family == AF_INET) { + if (session->connection.localaddr.ss_family == AF_INET) { struct capwap_localipv4_element addr; - memcpy(&addr.address, &((struct sockaddr_in*)&session->acctrladdress)->sin_addr, sizeof(struct in_addr)); + memcpy(&addr.address, &((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, sizeof(struct in_addr)); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr); - } else if (session->acctrladdress.ss_family == AF_INET6) { + } else if (session->connection.localaddr.ss_family == AF_INET6) { struct capwap_localipv6_element addr; - memcpy(&addr.address, &((struct sockaddr_in6*)&session->acctrladdress)->sin6_addr, sizeof(struct in6_addr)); + memcpy(&addr.address, &((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, sizeof(struct in6_addr)); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr); } @@ -668,7 +668,7 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash); /* Send Join response to WTP */ - if (capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->responsefragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (CAPWAP_RESULTCODE_OK(resultcode.code)) { ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE); } else { diff --git a/src/ac/ac_dfa_reset.c b/src/ac/ac_dfa_reset.c index 36ce8f1..2dcc064 100644 --- a/src/ac/ac_dfa_reset.c +++ b/src/ac/ac_dfa_reset.c @@ -31,8 +31,8 @@ void ac_dfa_state_reset(struct ac_session_t* session, struct capwap_parsed_packe ac_free_reference_last_request(session); ac_session_teardown(session); } else { - /* Retransmit configuration request */ - if (!capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->requestfragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + /* Retransmit configuration request */ + if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { capwap_logging_debug("Warning: error to resend reset request packet"); } diff --git a/src/ac/ac_dfa_run.c b/src/ac/ac_dfa_run.c index aa9dadf..648405f 100644 --- a/src/ac/ac_dfa_run.c +++ b/src/ac/ac_dfa_run.c @@ -53,7 +53,7 @@ static int receive_echo_request(struct ac_session_t* session, struct capwap_pars capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash); /* Send Configure response to WTP */ - if (!capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->responsefragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { /* Response is already created and saved. When receive a re-request, DFA autoresponse */ capwap_logging_debug("Warning: error to send echo response packet"); } @@ -61,118 +61,70 @@ static int receive_echo_request(struct ac_session_t* session, struct capwap_pars return 0; } -/* */ -static int ac_send_data_keepalive(struct ac_session_t* session, struct capwap_parsed_packet* packet) { - struct capwap_list* txfragpacket; - struct capwap_header_data capwapheader; - struct capwap_packet_txmng* txmngpacket; - int result = -1; - - /* Build packet */ - capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(packet->rxmngpacket->header)); - capwap_header_set_keepalive_flag(&capwapheader, 1); - txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, session->mtu); - - /* Add message element */ - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &session->sessionid); - - /* Data keepalive complete, get fragment packets into local list */ - txfragpacket = capwap_list_create(); - capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0); - if (txfragpacket->count == 1) { - /* Send Data keepalive to WTP */ - if (capwap_crypt_sendto_fragmentpacket(&session->datadtls, session->datasocket.socket[session->datasocket.type], txfragpacket, &session->acdataaddress, &session->wtpdataaddress)) { - result = 0; - } else { - capwap_logging_debug("Warning: error to send data channel keepalive packet"); - } - } else { - capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet"); - } - - /* Free packets manager */ - capwap_list_free(txfragpacket); - capwap_packet_txmng_free(txmngpacket); - - return result; -} - /* */ void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet* packet) { ASSERT(session != NULL); if (packet) { - if (packet->rxmngpacket->isctrlpacket) { - if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((session->localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { - switch (packet->rxmngpacket->ctrlmsg.type) { - case CAPWAP_CONFIGURATION_UPDATE_RESPONSE: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_CHANGE_STATE_EVENT_REQUEST: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_ECHO_REQUEST: { - if (!receive_echo_request(session, packet)) { - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - } else { - ac_session_teardown(session); - } - - break; - } - - case CAPWAP_CLEAR_CONFIGURATION_RESPONSE: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_WTP_EVENT_REQUEST: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_DATA_TRANSFER_REQUEST: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_DATA_TRANSFER_RESPONSE: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_STATION_CONFIGURATION_RESPONSE: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } - - case CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE: { - /* TODO */ - capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - break; - } + if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((session->localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { + switch (packet->rxmngpacket->ctrlmsg.type) { + case CAPWAP_CONFIGURATION_UPDATE_RESPONSE: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; } - } - } else { - if (IS_FLAG_K_HEADER(packet->rxmngpacket->header)) { - if (!memcmp(capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID), &session->sessionid, sizeof(struct capwap_sessionid_element))) { - if (ac_send_data_keepalive(session, packet)) { + + case CAPWAP_CHANGE_STATE_EVENT_REQUEST: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_ECHO_REQUEST: { + if (!receive_echo_request(session, packet)) { + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + } else { ac_session_teardown(session); } + + break; + } + + case CAPWAP_CLEAR_CONFIGURATION_RESPONSE: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_WTP_EVENT_REQUEST: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_DATA_TRANSFER_REQUEST: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_DATA_TRANSFER_RESPONSE: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_STATION_CONFIGURATION_RESPONSE: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; + } + + case CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE: { + /* TODO */ + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + break; } - } else { - /* TODO */ } } } else { @@ -207,7 +159,7 @@ void ac_session_reset(struct ac_session_t* session, struct capwap_imageidentifie capwap_packet_txmng_free(txmngpacket); /* Send Configure response to WTP */ - if (capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], session->requestfragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) { + if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { session->dfa.rfcRetransmitCount = 0; capwap_killall_timeout(&session->timeout); capwap_set_timeout(session->dfa.rfcRetransmitInterval, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); diff --git a/src/ac/ac_execute.c b/src/ac/ac_execute.c index c2024ec..52c8bed 100644 --- a/src/ac/ac_execute.c +++ b/src/ac/ac_execute.c @@ -70,6 +70,8 @@ static void ac_wait_terminate_allsessions(void) { ac_session_msgqueue_parsing_item(&item); } } + + capwap_logging_debug("Close all sessions"); } /* Initialize message queue */ @@ -138,7 +140,7 @@ static int ac_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size } /* Add packet to session */ -static void ac_session_add_packet(struct ac_session_t* session, char* buffer, int size, int isctrlsocket, int plainbuffer) { +static void ac_session_add_packet(struct ac_session_t* session, char* buffer, int size, int plainbuffer) { struct capwap_list_item* item; struct ac_packet* packet; @@ -154,11 +156,33 @@ static void ac_session_add_packet(struct ac_session_t* session, char* buffer, in /* Append to packets list */ capwap_lock_enter(&session->sessionlock); - capwap_itemlist_insert_after((isctrlsocket ? session->controlpackets : session->datapackets), NULL, item); + capwap_itemlist_insert_after(session->packets, NULL, item); capwap_event_signal(&session->waitpacket); capwap_lock_exit(&session->sessionlock); } +/* Add packet to session data */ +static void ac_session_data_add_packet(struct ac_session_data_t* sessiondata, char* buffer, int size, int plainbuffer) { + struct capwap_list_item* item; + struct ac_packet* packet; + + ASSERT(sessiondata != NULL); + ASSERT(buffer != NULL); + ASSERT(size > 0); + + /* Copy packet */ + item = capwap_itemlist_create(sizeof(struct ac_packet) + size); + packet = (struct ac_packet*)item->item; + packet->plainbuffer = plainbuffer; + memcpy(packet->buffer, buffer, size); + + /* Append to packets list */ + capwap_lock_enter(&sessiondata->sessionlock); + capwap_itemlist_insert_after(sessiondata->packets, NULL, item); + capwap_event_signal(&sessiondata->waitpacket); + capwap_lock_exit(&sessiondata->sessionlock); +} + /* Add action to session */ void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length) { struct capwap_list_item* item; @@ -180,13 +204,39 @@ void ac_session_send_action(struct ac_session_t* session, long action, long para /* Append to actions list */ capwap_lock_enter(&session->sessionlock); - capwap_itemlist_insert_after(session->actionsession, NULL, item); + capwap_itemlist_insert_after(session->action, NULL, item); capwap_event_signal(&session->waitpacket); capwap_lock_exit(&session->sessionlock); } +/* Add action to session data */ +void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length) { + struct capwap_list_item* item; + struct ac_session_action* actionsession; + + ASSERT(sessiondata != NULL); + ASSERT(length >= 0); + + /* */ + item = capwap_itemlist_create(sizeof(struct ac_session_action) + length); + actionsession = (struct ac_session_action*)item->item; + actionsession->action = action; + actionsession->param = param; + actionsession->length = length; + if (length > 0) { + ASSERT(data != NULL); + memcpy(actionsession->data, data, length); + } + + /* Append to actions list */ + capwap_lock_enter(&sessiondata->sessionlock); + capwap_itemlist_insert_after(sessiondata->action, NULL, item); + capwap_event_signal(&sessiondata->waitpacket); + capwap_lock_exit(&sessiondata->sessionlock); +} + /* Find AC sessions */ -static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_storage* address, int isctrlsocket) { +static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_storage* address) { struct ac_session_t* result = NULL; struct capwap_list_item* search; @@ -199,10 +249,11 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st struct ac_session_t* session = (struct ac_session_t*)search->item; ASSERT(session != NULL); - if (!capwap_compare_ip(address, (isctrlsocket ? &session->wtpctrladdress : &session->wtpdataaddress))) { + if (!capwap_compare_ip(address, &session->connection.remoteaddr)) { /* Increment session count */ capwap_lock_enter(&session->sessionlock); session->count++; + capwap_event_signal(&session->changereference); capwap_lock_exit(&session->sessionlock); /* */ @@ -218,28 +269,29 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st return result; } -/* Find session from session id */ -struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid) { - struct ac_session_t* result = NULL; +/* Find AC sessions data */ +static struct ac_session_data_t* ac_search_session_data_from_wtpaddress(struct sockaddr_storage* address) { + struct ac_session_data_t* result = NULL; struct capwap_list_item* search; - ASSERT(sessionid != NULL); + ASSERT(address != NULL); capwap_rwlock_rdlock(&g_ac.sessionslock); - search = g_ac.sessions->first; + search = g_ac.sessionsdata->first; while (search != NULL) { - struct ac_session_t* session = (struct ac_session_t*)search->item; - ASSERT(session != NULL); + struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item; + ASSERT(sessiondata != NULL); - if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) { - /* Increment session count */ - capwap_lock_enter(&session->sessionlock); - session->count++; - capwap_lock_exit(&session->sessionlock); + if (!capwap_compare_ip(address, &sessiondata->connection.remoteaddr)) { + /* Increment session data count */ + capwap_lock_enter(&sessiondata->sessionlock); + sessiondata->count++; + capwap_event_signal(&sessiondata->changereference); + capwap_lock_exit(&sessiondata->sessionlock); /* */ - result = session; + result = sessiondata; break; } @@ -269,6 +321,7 @@ struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) { /* Increment session count */ capwap_lock_enter(&session->sessionlock); session->count++; + capwap_event_signal(&session->changereference); capwap_lock_exit(&session->sessionlock); /* */ @@ -359,75 +412,6 @@ char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata) { return wtpid; } -/* */ -static struct ac_session_t* ac_get_session_from_keepalive(void* buffer, int buffersize) { - struct capwap_parsed_packet packet; - struct capwap_packet_rxmng* rxmngpacket; - struct ac_session_t* result = NULL; - - ASSERT(buffer != NULL); - ASSERT(buffersize > 0); - - /* Build receive manager CAPWAP message */ - rxmngpacket = capwap_packet_rxmng_create_message(0); - if (capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, buffersize) != CAPWAP_RECEIVE_COMPLETE_PACKET) { - /* Accept only keep alive without fragmentation */ - capwap_packet_rxmng_free(rxmngpacket); - capwap_logging_debug("Receive data keep alive packet fragmentated"); - return NULL; - } - - /* Validate message */ - if (capwap_check_message_type(rxmngpacket) != VALID_MESSAGE_TYPE) { - /* Invalid message */ - capwap_packet_rxmng_free(rxmngpacket); - capwap_logging_debug("Invalid data packet message type"); - return NULL; - } - - /* Parsing packet */ - if (!capwap_parsing_packet(rxmngpacket, NULL, &packet)) { - /* Validate packet */ - if (!capwap_validate_parsed_packet(&packet, NULL)) { - struct capwap_list_item* search; - struct capwap_sessionid_element* sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(&packet, CAPWAP_ELEMENT_SESSIONID); - - capwap_rwlock_rdlock(&g_ac.sessionslock); - - search = g_ac.sessions->first; - while (search != NULL) { - struct ac_session_t* session = (struct ac_session_t*)search->item; - ASSERT(session != NULL); - - if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) { - /* Increment session count */ - capwap_lock_enter(&session->sessionlock); - session->count++; - capwap_lock_exit(&session->sessionlock); - - /* */ - result = session; - break; - } - - search = search->next; - } - - capwap_rwlock_exit(&g_ac.sessionslock); - } else { - capwap_logging_debug("Failed validation parsed data packet"); - } - } else { - capwap_logging_debug("Failed parsing data packet"); - } - - /* Free resource */ - capwap_free_parsed_packet(&packet); - capwap_packet_rxmng_free(rxmngpacket); - - return result; -} - /* */ void ac_session_close(struct ac_session_t* session) { capwap_lock_enter(&session->sessionlock); @@ -436,12 +420,21 @@ void ac_session_close(struct ac_session_t* session) { capwap_lock_exit(&session->sessionlock); } +/* */ +void ac_session_data_close(struct ac_session_data_t* sessiondata) { + capwap_lock_enter(&sessiondata->sessionlock); + sessiondata->running = 0; + capwap_event_signal(&sessiondata->waitpacket); + capwap_lock_exit(&sessiondata->sessionlock); +} + /* Close sessions */ static void ac_close_sessions() { struct capwap_list_item* search; capwap_rwlock_rdlock(&g_ac.sessionslock); + /* Session */ search = g_ac.sessions->first; while (search != NULL) { struct ac_session_t* session = (struct ac_session_t*)search->item; @@ -452,136 +445,45 @@ static void ac_close_sessions() { search = search->next; } + /* Session data */ + search = g_ac.sessionsdata->first; + while (search != NULL) { + struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item; + ASSERT(sessiondata != NULL); + + ac_session_data_close(sessiondata); + + search = search->next; + } + capwap_rwlock_exit(&g_ac.sessionslock); } -/* DTLS Handshake BIO send */ -static int ac_bio_handshake_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) { - struct ac_data_session_handshake* handshake = (struct ac_data_session_handshake*)param; - return capwap_sendto(handshake->socket.socket[handshake->socket.type], buffer, length, &handshake->acaddress, &handshake->wtpaddress); -} - -/* Find AC sessions */ -static void ac_update_session_from_datapacket(struct capwap_socket* socket, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, void* buffer, int buffersize) { - struct ac_session_t* session = NULL; +/* Detect data channel */ +static int ac_is_plain_datachannel(void* buffer, int buffersize) { struct capwap_preamble* preamble = (struct capwap_preamble*)buffer; ASSERT(buffer != NULL); ASSERT(buffersize > sizeof(struct capwap_preamble)); - ASSERT(socket != NULL); - ASSERT(recvfromaddr != NULL); - ASSERT(recvtoaddr != NULL); - /* */ - if (preamble->type == CAPWAP_PREAMBLE_HEADER) { - if ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED) != 0) { - session = ac_get_session_from_keepalive(buffer, buffersize); - if (session) { - /* Update data session */ - memcpy(&session->datasocket, socket, sizeof(struct capwap_socket)); - memcpy(&session->acdataaddress, recvtoaddr, sizeof(struct sockaddr_storage)); - memcpy(&session->wtpdataaddress, recvfromaddr, sizeof(struct sockaddr_storage)); - - /* Add packet*/ - ac_session_add_packet(session, buffer, buffersize, 0, 1); - ac_session_release_reference(session); - } - } - } else if (preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) { - if ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) != 0) { - struct capwap_list_item* itemlist; - struct ac_data_session_handshake* handshake; - - /* Search active data dtls handshake */ - itemlist = g_ac.datasessionshandshake->first; - while (itemlist != NULL) { - handshake = (struct ac_data_session_handshake*)itemlist->item; - - if (!capwap_compare_ip(recvfromaddr, &handshake->wtpaddress) && !capwap_compare_ip(recvtoaddr, &handshake->acaddress)) { - break; - } - - /* Next */ - itemlist = itemlist->next; - } - - /* Create new DTLS handshake */ - if (!itemlist) { - itemlist = capwap_itemlist_create(sizeof(struct ac_data_session_handshake)); - handshake = (struct ac_data_session_handshake*)itemlist->item; - memset(handshake, 0, sizeof(struct ac_data_session_handshake)); - - /* */ - memcpy(&handshake->socket, socket, sizeof(struct capwap_socket)); - memcpy(&handshake->acaddress, recvtoaddr, sizeof(struct sockaddr_storage)); - memcpy(&handshake->wtpaddress, recvfromaddr, sizeof(struct sockaddr_storage)); - - /* Create DTLS session */ - if (!capwap_crypt_createsession(&handshake->dtls, CAPWAP_DTLS_DATA_SESSION, &g_ac.dtlscontext, ac_bio_handshake_send, handshake)) { - capwap_itemlist_free(itemlist); - itemlist = NULL; - } else { - if (capwap_crypt_open(&handshake->dtls, recvfromaddr) == CAPWAP_HANDSHAKE_ERROR) { - capwap_crypt_freesession(&handshake->dtls); - capwap_itemlist_free(itemlist); - itemlist = NULL; - } else { - /* Add item to list */ - capwap_itemlist_insert_after(g_ac.datasessionshandshake, NULL, itemlist); - } - } - } - - /* Decrypt packet */ - if (itemlist) { - char temp[CAPWAP_MAX_PACKET_SIZE]; - - /* */ - handshake = (struct ac_data_session_handshake*)itemlist->item; - buffersize = capwap_decrypt_packet(&handshake->dtls, buffer, buffersize, temp, CAPWAP_MAX_PACKET_SIZE); - if (buffersize > 0) { - session = ac_get_session_from_keepalive(temp, buffersize); - if (!session) { - capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist); - capwap_crypt_close(&handshake->dtls); - capwap_crypt_freesession(&handshake->dtls); - capwap_itemlist_free(itemlist); - } else { - /* Update DTLS session */ - capwap_crypt_change_dtls(&handshake->dtls, &session->datadtls); - memcpy(&session->datasocket, &handshake->socket, sizeof(struct capwap_socket)); - memcpy(&session->acdataaddress, &handshake->acaddress, sizeof(struct sockaddr_storage)); - memcpy(&session->wtpdataaddress, &handshake->wtpaddress, sizeof(struct sockaddr_storage)); - capwap_crypt_change_bio_send(&session->datadtls, ac_bio_send, session); - - /* Remove temp element */ - capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist); - capwap_itemlist_free(itemlist); - - /* Add packet*/ - ac_session_add_packet(session, temp, buffersize, 0, 1); /* Packet already decrypt */ - ac_session_release_reference(session); - } - } else if ((buffersize == CAPWAP_ERROR_SHUTDOWN) || (buffersize == CAPWAP_ERROR_CLOSE)) { - capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist); - capwap_crypt_close(&handshake->dtls); - capwap_crypt_freesession(&handshake->dtls); - capwap_itemlist_free(itemlist); - } - } - } + if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED) != 0)) { + return 1; + } else if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) != 0)) { + return 0; } + + return -1; } /* Create new session */ -static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* ctrlsock) { +static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock) { int result; struct capwap_list_item* itemlist; struct ac_session_t* session; ASSERT(acaddress != NULL); ASSERT(wtpaddress != NULL); - ASSERT(ctrlsock != NULL); + ASSERT(sock != NULL); /* Create new session */ itemlist = capwap_itemlist_create(sizeof(struct ac_session_t)); @@ -590,11 +492,18 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres session->itemlist = itemlist; session->running = 1; + + memcpy(&session->connection.socket, sock, sizeof(struct capwap_socket)); + memcpy(&session->connection.localaddr, acaddress, sizeof(struct sockaddr_storage)); + memcpy(&session->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage)); + + /* */ session->count = 2; - memcpy(&session->acctrladdress, acaddress, sizeof(struct sockaddr_storage)); - memcpy(&session->wtpctrladdress, wtpaddress, sizeof(struct sockaddr_storage)); - memcpy(&session->ctrlsocket, ctrlsock, sizeof(struct capwap_socket)); - + capwap_event_init(&session->changereference); + + /* */ + capwap_init_timeout(&session->timeout); + /* Duplicate state for DFA */ memcpy(&session->dfa, &g_ac.dfa, sizeof(struct ac_state)); session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses); @@ -606,12 +515,12 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres /* Add default AC list if empty*/ if ((session->dfa.acipv4list.addresses->count == 0) && (session->dfa.acipv6list.addresses->count == 0)) { - if (session->acctrladdress.ss_family == AF_INET) { + if (acaddress->ss_family == AF_INET) { struct in_addr* acip = (struct in_addr*)capwap_array_get_item_pointer(session->dfa.acipv4list.addresses, 0); - memcpy(acip, &((struct sockaddr_in*)&session->acctrladdress)->sin_addr, sizeof(struct in_addr)); - } else if (session->acctrladdress.ss_family == AF_INET6) { + memcpy(acip, &((struct sockaddr_in*)acaddress)->sin_addr, sizeof(struct in_addr)); + } else if (acaddress->ss_family == AF_INET6) { struct in6_addr* acip = (struct in6_addr*)capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0); - memcpy(acip, &((struct sockaddr_in6*)&session->acctrladdress)->sin6_addr, sizeof(struct in6_addr)); + memcpy(acip, &((struct sockaddr_in6*)acaddress)->sin6_addr, sizeof(struct in6_addr)); } } @@ -619,9 +528,8 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres capwap_event_init(&session->waitpacket); capwap_lock_init(&session->sessionlock); - session->actionsession = capwap_list_create(); - session->controlpackets = capwap_list_create(); - session->datapackets = capwap_list_create(); + session->action = capwap_list_create(); + session->packets = capwap_list_create(); session->requestfragmentpacket = capwap_list_create(); session->responsefragmentpacket = capwap_list_create(); @@ -653,19 +561,93 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres return session; } +/* Create new session data */ +static struct ac_session_data_t* ac_create_session_data(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock, int plain) { + int result; + struct capwap_list_item* itemlist; + struct ac_session_data_t* sessiondata; + + ASSERT(acaddress != NULL); + ASSERT(wtpaddress != NULL); + ASSERT(sock != NULL); + + /* Create new session data */ + itemlist = capwap_itemlist_create(sizeof(struct ac_session_data_t)); + sessiondata = (struct ac_session_data_t*)itemlist->item; + memset(sessiondata, 0, sizeof(struct ac_session_data_t)); + + /* */ + sessiondata->itemlist = itemlist; + sessiondata->running = 1; + sessiondata->enabledtls = (plain ? 0 : 1); + + /* */ + sessiondata->count = 2; + capwap_event_init(&sessiondata->changereference); + + /* */ + capwap_init_timeout(&sessiondata->timeout); + + /* Connection info */ + memcpy(&sessiondata->connection.socket, sock, sizeof(struct capwap_socket)); + memcpy(&sessiondata->connection.localaddr, acaddress, sizeof(struct sockaddr_storage)); + memcpy(&sessiondata->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage)); + sessiondata->mtu = g_ac.mtu; + + /* Init */ + capwap_event_init(&sessiondata->waitpacket); + capwap_lock_init(&sessiondata->sessionlock); + + sessiondata->action = capwap_list_create(); + sessiondata->packets = capwap_list_create(); + + /* Update session data list */ + capwap_rwlock_wrlock(&g_ac.sessionslock); + capwap_itemlist_insert_after(g_ac.sessionsdata, NULL, itemlist); + capwap_rwlock_exit(&g_ac.sessionslock); + + /* Create thread */ + result = pthread_create(&sessiondata->threadid, NULL, ac_session_data_thread, (void*)sessiondata); + if (!result) { + struct ac_session_thread_t* sessionthread; + + /* Keeps trace of active threads */ + itemlist = capwap_itemlist_create(sizeof(struct ac_session_thread_t)); + sessionthread = (struct ac_session_thread_t*)itemlist->item; + sessionthread->threadid = sessiondata->threadid; + + /* */ + capwap_itemlist_insert_after(g_ac.sessionsthread, NULL, itemlist); + } else { + capwap_logging_fatal("Unable create session data thread, error code %d", result); + capwap_exit(CAPWAP_OUT_OF_MEMORY); + } + + return sessiondata; +} + /* Release reference of session */ void ac_session_release_reference(struct ac_session_t* session) { ASSERT(session != NULL); capwap_lock_enter(&session->sessionlock); - - /* Release reference must not destroy device, reference count > 0 */ - session->count--; ASSERT(session->count > 0); - + session->count--; + capwap_event_signal(&session->changereference); capwap_lock_exit(&session->sessionlock); } +/* Release reference of session data */ +void ac_session_data_release_reference(struct ac_session_data_t* sessiondata) { + ASSERT(sessiondata != NULL); + + capwap_lock_enter(&sessiondata->sessionlock); + ASSERT(sessiondata->count > 0); + sessiondata->count--; + capwap_event_signal(&sessiondata->changereference); + capwap_lock_exit(&sessiondata->sessionlock); +} + /* Update statistics */ void ac_update_statistics(void) { @@ -694,10 +676,6 @@ int ac_execute(void) { int isctrlsocket = 0; struct sockaddr_storage recvfromaddr; struct sockaddr_storage recvtoaddr; - int isrecvpacket = 0; - - struct ac_session_t* session; - struct capwap_socket ctrlsock; char buffer[CAPWAP_MAX_PACKET_SIZE]; int buffersize; @@ -738,7 +716,6 @@ int ac_execute(void) { /* */ while (g_ac.running) { /* Receive packet */ - isrecvpacket = 0; buffersize = sizeof(buffer); index = ac_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, NULL); if (!g_ac.running) { @@ -763,81 +740,115 @@ int ac_execute(void) { } } - /* Search the AC session */ + /* Search the AC session / session data */ isctrlsocket = ((index < (fdscount / 2)) ? 1 : 0); - session = ac_search_session_from_wtpaddress(&recvfromaddr, isctrlsocket); + if (isctrlsocket) { + struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr); - if (session) { - /* Add packet*/ - ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0); + if (session) { + /* Add packet*/ + ac_session_add_packet(session, buffer, buffersize, 0); - /* Release reference */ - ac_session_release_reference(session); - } else { - if (isctrlsocket) { + /* Release reference */ + ac_session_release_reference(session); + } else { unsigned short sessioncount; + /* TODO prevent dos attack add filtering ip for multiple error */ + /* Get current session number */ capwap_rwlock_rdlock(&g_ac.sessionslock); sessioncount = g_ac.sessions->count; capwap_rwlock_exit(&g_ac.sessionslock); /* PreParsing packet for reduce a DoS attack */ - check = capwap_sanity_check(isctrlsocket, CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls, 0); - if (check == CAPWAP_PLAIN_PACKET) { - struct capwap_header* header = (struct capwap_header*)buffer; + if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) { + check = capwap_sanity_check(1, CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls, 0); + if (check == CAPWAP_PLAIN_PACKET) { + struct capwap_header* header = (struct capwap_header*)buffer; - /* Accepted only packet without fragmentation */ - if (!IS_FLAG_F_HEADER(header)) { - int headersize = GET_HLEN_HEADER(header) * 4; - if (buffersize >= (headersize + sizeof(struct capwap_control_message))) { - struct capwap_control_message* control = (struct capwap_control_message*)((char*)buffer + headersize); - unsigned long type = ntohl(control->type); + /* Accepted only packet without fragmentation */ + if (!IS_FLAG_F_HEADER(header)) { + int headersize = GET_HLEN_HEADER(header) * 4; + if (buffersize >= (headersize + sizeof(struct capwap_control_message))) { + struct capwap_control_message* control = (struct capwap_control_message*)((char*)buffer + headersize); + unsigned long type = ntohl(control->type); - if (type == CAPWAP_DISCOVERY_REQUEST) { - if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) { + if (type == CAPWAP_DISCOVERY_REQUEST) { ac_discovery_add_packet(buffer, buffersize, fds[index].fd, &recvfromaddr); - } - } else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) { - if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) { + } else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) { + struct capwap_socket ctrlsock; + /* Retrive socket info */ capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd); /* Create a new session */ session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock); - ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 1); + ac_session_add_packet(session, buffer, buffersize, 1); /* Release reference */ ac_session_release_reference(session); } } } - } - } else if (check == CAPWAP_DTLS_PACKET) { - /* Before create new session check if receive DTLS Client Hello */ - if (capwap_sanity_check_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) { - /* Need create a new session for check if it is a valid DTLS handshake */ - if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) { - /* TODO prevent dos attack add filtering ip for multiple error */ + } else if (check == CAPWAP_DTLS_PACKET) { + /* Before create new session check if receive DTLS Client Hello */ + if (capwap_sanity_check_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) { + struct capwap_socket ctrlsock; /* Retrive socket info */ capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd); /* Create a new session */ session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock); - ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0); + ac_session_add_packet(session, buffer, buffersize, 0); /* Release reference */ ac_session_release_reference(session); } } } - } else { - struct capwap_socket datasocket; + } + } else { + struct ac_session_data_t* sessiondata = ac_search_session_data_from_wtpaddress(&recvfromaddr); - /* Retrieve session by sessionid of data packet */ - capwap_get_network_socket(&g_ac.net, &datasocket, fds[index].fd); - ac_update_session_from_datapacket(&datasocket, &recvfromaddr, &recvtoaddr, buffer, buffersize); + if (sessiondata) { + /* Add packet*/ + ac_session_data_add_packet(sessiondata, buffer, buffersize, 0); + + /* Release reference */ + ac_session_data_release_reference(sessiondata); + } else { + int plain; + + /* TODO prevent dos attack add filtering ip for multiple error */ + + /* Detect type data channel */ + plain = ac_is_plain_datachannel(buffer, buffersize); + + /* Before create new session check if receive DTLS Client Hello */ + if (!plain) { + if (buffersize <= sizeof(struct capwap_dtls_header)) { + plain = -1; + } else if (!capwap_sanity_check_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) { + plain = -1; + } + } + + /* */ + if (plain >= 0) { + struct capwap_socket datasock; + + /* Retrive socket info */ + capwap_get_network_socket(&g_ac.net, &datasock, fds[index].fd); + + /* Create a new session */ + sessiondata = ac_create_session_data(&recvfromaddr, &recvtoaddr, &datasock, plain); + ac_session_data_add_packet(sessiondata, buffer, buffersize, 0); + + /* Release reference */ + ac_session_data_release_reference(sessiondata); + } } } } else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE)) { @@ -861,17 +872,6 @@ int ac_execute(void) { /* Wait to terminate all sessions */ ac_wait_terminate_allsessions(); - /* Free handshake session */ - while (g_ac.datasessionshandshake->first != NULL) { - struct ac_data_session_handshake* handshake = (struct ac_data_session_handshake*)g_ac.datasessionshandshake->first->item; - - if (handshake->dtls.enable) { - capwap_crypt_freesession(&handshake->dtls); - } - - capwap_itemlist_free(capwap_itemlist_remove(g_ac.datasessionshandshake, g_ac.datasessionshandshake->first)); - } - /* Free memory */ capwap_free(fds); return result; diff --git a/src/ac/ac_session.c b/src/ac/ac_session.c index e6bf1ba..d40c862 100644 --- a/src/ac/ac_session.c +++ b/src/ac/ac_session.c @@ -3,14 +3,14 @@ #include "capwap_dfa.h" #include "ac_session.h" #include "ac_backend.h" +#include -#define PACKET_TIMEOUT -1 -#define DTLS_SHUTDOWN -2 -#define ACTION_SESSION -3 +#define AC_ERROR_TIMEOUT -1000 +#define AC_ERROR_ACTION_SESSION -1001 /* */ static int ac_session_action_execute(struct ac_session_t* session, struct ac_session_action* action) { - int result = ACTION_SESSION; + int result = AC_ERROR_ACTION_SESSION; switch (action->action) { case AC_SESSION_ACTION_RESET_WTP: { @@ -26,13 +26,34 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses break; } + + case AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA: { + int valid = 0; + struct ac_soap_response* response; + + /* Capwap handshake complete, notify event to backend */ + response = ac_soap_runningwtpsession(session, session->wtpid); + if (response) { + valid = ((response->responsecode == HTTP_RESULT_OK) ? 1 : 0); + ac_soapclient_free_response(response); + } + + if (valid) { + ac_dfa_change_state(session, CAPWAP_RUN_STATE); + capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); + } else { + result = CAPWAP_ERROR_CLOSE; + } + + break; + } } return result; } /* */ -static int ac_network_read(struct ac_session_t* session, void* buffer, int length, int* isctrlpacket, struct timeout_control* timeout) { +static int ac_network_read(struct ac_session_t* session, void* buffer, int length, struct timeout_control* timeout) { int result = 0; long indextimer; long waittimeout; @@ -40,18 +61,17 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt ASSERT(session != NULL); ASSERT(buffer != NULL); ASSERT(length > 0); - ASSERT(isctrlpacket != NULL); for (;;) { capwap_lock_enter(&session->sessionlock); if (!session->running) { capwap_lock_exit(&session->sessionlock); - return DTLS_SHUTDOWN; - } else if (!session->waitresponse && (session->actionsession->count > 0)) { + return CAPWAP_ERROR_CLOSE; + } else if (!session->waitresponse && (session->action->count > 0)) { struct capwap_list_item* itemaction; - itemaction = capwap_itemlist_remove_head(session->actionsession); + itemaction = capwap_itemlist_remove_head(session->action); capwap_lock_exit(&session->sessionlock); /* */ @@ -60,44 +80,32 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt /* Free packet */ capwap_itemlist_free(itemaction); return result; - } else if ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) { + } else if (session->packets->count > 0) { struct capwap_list_item* itempacket; - *isctrlpacket = ((session->controlpackets->count > 0) ? 1 : 0); - if (*isctrlpacket) { - capwap_logging_debug("Receive control packet"); - } else { - capwap_logging_debug("Receive data packet"); - } + capwap_logging_debug("Receive control packet"); /* Get packet */ - itempacket = capwap_itemlist_remove_head((*isctrlpacket ? session->controlpackets : session->datapackets)); + itempacket = capwap_itemlist_remove_head(session->packets); capwap_lock_exit(&session->sessionlock); if (itempacket) { struct ac_packet* packet = (struct ac_packet*)itempacket->item; long packetlength = itempacket->itemsize - sizeof(struct ac_packet); - struct capwap_dtls* dtls = (*isctrlpacket ? &session->ctrldtls : &session->datadtls); - if (!packet->plainbuffer && dtls->enable) { - int oldaction = dtls->action; + if (!packet->plainbuffer && session->dtls.enable) { + int oldaction = session->dtls.action; /* Decrypt packet */ - result = capwap_decrypt_packet(dtls, packet->buffer, packetlength, buffer, length); + result = capwap_decrypt_packet(&session->dtls, packet->buffer, packetlength, buffer, length); if (result == CAPWAP_ERROR_AGAIN) { /* Check is handshake complete */ - if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) { - if (*isctrlpacket) { - if (session->state == CAPWAP_DTLS_CONNECT_STATE) { - ac_dfa_change_state(session, CAPWAP_JOIN_STATE); - capwap_set_timeout(session->dfa.rfcWaitJoin, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); - } + if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (session->dtls.action == CAPWAP_DTLS_ACTION_DATA)) { + if (session->state == CAPWAP_DTLS_CONNECT_STATE) { + ac_dfa_change_state(session, CAPWAP_JOIN_STATE); + capwap_set_timeout(session->dfa.rfcWaitJoin, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION); } } - } else if (result == CAPWAP_ERROR_SHUTDOWN) { - if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) { - result = DTLS_SHUTDOWN; - } } } else { if (packetlength <= length) { @@ -119,7 +127,7 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt capwap_update_timeout(timeout); waittimeout = capwap_get_timeout(timeout, &indextimer); if ((waittimeout <= 0) && (indextimer != CAPWAP_TIMER_UNDEF)) { - return PACKET_TIMEOUT; + return AC_ERROR_TIMEOUT; } /* Wait packet */ @@ -188,39 +196,7 @@ static void ac_dfa_execute(struct ac_session_t* session, struct capwap_parsed_pa } /* */ -static struct capwap_packet_rxmng* ac_get_packet_rxmng(struct ac_session_t* session, int isctrlmsg) { - struct capwap_packet_rxmng* rxmngpacket = NULL; - - if (isctrlmsg) { - if (!session->rxmngctrlpacket) { - session->rxmngctrlpacket = capwap_packet_rxmng_create_message(1); - } - - rxmngpacket = session->rxmngctrlpacket; - } else { - if (!session->rxmngdatapacket) { - session->rxmngdatapacket = capwap_packet_rxmng_create_message(0); - } - - rxmngpacket = session->rxmngdatapacket; - } - - return rxmngpacket; -} - -/* */ -static void ac_free_packet_rxmng(struct ac_session_t* session, int isctrlmsg) { - if (isctrlmsg && session->rxmngctrlpacket) { - capwap_packet_rxmng_free(session->rxmngctrlpacket); - session->rxmngctrlpacket = NULL; - } else if (!isctrlmsg && session->rxmngdatapacket) { - capwap_packet_rxmng_free(session->rxmngdatapacket); - session->rxmngdatapacket = NULL; - } -} - -/* */ -static void ac_send_invalid_request(struct ac_session_t* session, struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, uint32_t errorcode) { +static void ac_send_invalid_request(struct ac_session_t* session, uint32_t errorcode) { struct capwap_header_data capwapheader; struct capwap_packet_txmng* txmngpacket; struct capwap_list* responsefragmentpacket; @@ -228,17 +204,17 @@ static void ac_send_invalid_request(struct ac_session_t* session, struct capwap_ struct capwap_header* header; struct capwap_resultcode_element resultcode = { .code = errorcode }; - ASSERT(rxmngpacket != NULL); - ASSERT(rxmngpacket->fragmentlist->first != NULL); - ASSERT(connection != NULL); + ASSERT(session != NULL); + ASSERT(session->rxmngpacket != NULL); + ASSERT(session->rxmngpacket->fragmentlist->first != NULL); /* */ - packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item; + packet = (struct capwap_fragment_packet_item*)session->rxmngpacket->fragmentlist->first->item; header = (struct capwap_header*)packet->buffer; /* Odd message type */ capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(header)); - txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, rxmngpacket->ctrlmsg.type + 1, rxmngpacket->ctrlmsg.seq, session->mtu); + txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, session->rxmngpacket->ctrlmsg.type + 1, session->rxmngpacket->ctrlmsg.seq, session->mtu); /* Add message element */ capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RESULTCODE, &resultcode); @@ -254,7 +230,7 @@ static void ac_send_invalid_request(struct ac_session_t* session, struct capwap_ capwap_packet_txmng_free(txmngpacket); /* Send unknown response */ - capwap_crypt_sendto_fragmentpacket(&session->ctrldtls, connection->socket.socket[connection->socket.type], responsefragmentpacket, &connection->localaddr, &connection->remoteaddr); + capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr); /* Don't buffering a packets sent */ capwap_list_free(responsefragmentpacket); @@ -262,17 +238,23 @@ static void ac_send_invalid_request(struct ac_session_t* session, struct capwap_ /* Release reference of session */ static void ac_session_destroy(struct ac_session_t* session) { - ASSERT(session != NULL); - - /* Free resource */ #ifdef DEBUG char sessionname[33]; +#endif - /* */ + ASSERT(session != NULL); + +#ifdef DEBUG capwap_sessionid_printf(&session->sessionid, sessionname); capwap_logging_debug("Release Session AC %s", sessionname); #endif + /* Release session data reference */ + if (session->sessiondata) { + ac_session_data_close(session->sessiondata); + ac_session_data_release_reference(session->sessiondata); + } + /* Release last reference */ capwap_lock_enter(&session->sessionlock); session->count--; @@ -287,36 +269,37 @@ static void ac_session_destroy(struct ac_session_t* session) { #ifdef DEBUG capwap_logging_debug("Wait for release Session AC %s (count=%d)", sessionname, session->count); #endif + /* */ + capwap_event_reset(&session->changereference); + capwap_lock_exit(&session->sessionlock); /* Wait */ - capwap_lock_exit(&session->sessionlock); - sleep(10); + capwap_event_wait(&session->changereference); + capwap_lock_enter(&session->sessionlock); } capwap_lock_exit(&session->sessionlock); /* Free DTSL Control */ - capwap_crypt_freesession(&session->ctrldtls); - - /* Free DTLS Data */ - capwap_crypt_freesession(&session->datadtls); + capwap_crypt_freesession(&session->dtls); /* Free resource */ - while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) { - capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets))); + while (session->packets->count > 0) { + capwap_itemlist_free(capwap_itemlist_remove_head(session->packets)); } /* */ + capwap_event_destroy(&session->changereference); capwap_event_destroy(&session->waitpacket); capwap_lock_destroy(&session->sessionlock); - capwap_list_free(session->actionsession); - capwap_list_free(session->controlpackets); - capwap_list_free(session->datapackets); + capwap_list_free(session->action); + capwap_list_free(session->packets); /* Free fragments packet */ - ac_free_packet_rxmng(session, 1); - ac_free_packet_rxmng(session, 0); + if (session->rxmngpacket) { + capwap_packet_rxmng_free(session->rxmngpacket); + } capwap_list_free(session->requestfragmentpacket); capwap_list_free(session->responsefragmentpacket); @@ -333,17 +316,50 @@ static void ac_session_destroy(struct ac_session_t* session) { capwap_itemlist_free(session->itemlist); } +/* */ +static void ac_session_report_connection(struct ac_session_t* session) { + char localip[INET6_ADDRSTRLEN + 10] = ""; + char remoteip[INET6_ADDRSTRLEN + 10] = ""; + + if (session->connection.localaddr.ss_family == AF_INET) { + char buffer[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.localaddr)->sin_port)); + } else if (session->connection.localaddr.ss_family == AF_INET6) { + char buffer[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.localaddr)->sin6_port)); + } + + if (session->connection.remoteaddr.ss_family == AF_INET) { + char buffer[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.remoteaddr)->sin_port)); + } else if (session->connection.remoteaddr.ss_family == AF_INET6) { + char buffer[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_port)); + } + + capwap_logging_info("Start control channel from %s to %s", remoteip, localip); +} + /* */ static void ac_session_run(struct ac_session_t* session) { int res; int check; int length; - int isctrlsocket; - struct capwap_connection connection; char buffer[CAPWAP_MAX_PACKET_SIZE]; ASSERT(session != NULL); + /* */ + ac_session_report_connection(session); + /* Configure DFA */ if (g_ac.enabledtls) { if (!ac_dtls_setup(session)) { @@ -357,93 +373,89 @@ static void ac_session_run(struct ac_session_t* session) { while (session->state != CAPWAP_DTLS_TEARDOWN_STATE) { /* Get packet */ - length = ac_network_read(session, buffer, sizeof(buffer), &isctrlsocket, &session->timeout); + length = ac_network_read(session, buffer, sizeof(buffer), &session->timeout); if (length < 0) { - if (length == PACKET_TIMEOUT) { + if (length == AC_ERROR_TIMEOUT) { ac_dfa_execute(session, NULL); - } else if (length == DTLS_SHUTDOWN) { + } else if ((length == CAPWAP_ERROR_SHUTDOWN) || (length == CAPWAP_ERROR_CLOSE)) { ac_session_teardown(session); - } else if (length == ACTION_SESSION) { - /* Nothing */ } } else if (length > 0) { - /* Accept data packet only in running state */ - if (isctrlsocket || (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) || (session->state == CAPWAP_RUN_STATE)) { - /* Check generic capwap packet */ - check = capwap_sanity_check(isctrlsocket, CAPWAP_UNDEF_STATE, buffer, length, 0, 0); - if (check == CAPWAP_PLAIN_PACKET) { - struct capwap_parsed_packet packet; - struct capwap_packet_rxmng* rxmngpacket; + /* Check generic capwap packet */ + check = capwap_sanity_check(1, CAPWAP_UNDEF_STATE, buffer, length, 0, 0); + if (check == CAPWAP_PLAIN_PACKET) { + struct capwap_parsed_packet packet; - /* Defragment management */ - rxmngpacket = ac_get_packet_rxmng(session, isctrlsocket); + /* Defragment management */ + if (!session->rxmngpacket) { + session->rxmngpacket = capwap_packet_rxmng_create_message(1); + } - /* If request, defragmentation packet */ - check = capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, length); - if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) { - int ignorepacket = 0; + /* If request, defragmentation packet */ + check = capwap_packet_rxmng_add_recv_packet(session->rxmngpacket, buffer, length); + if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) { + int ignorepacket = 0; - /* Receive all fragment */ - memcpy(&connection.socket, (isctrlsocket ? &session->ctrlsocket : &session->datasocket), sizeof(struct capwap_socket)); - memcpy(&connection.localaddr, (isctrlsocket ? &session->acctrladdress : &session->acdataaddress), sizeof(struct sockaddr_storage)); - memcpy(&connection.remoteaddr, (isctrlsocket ? &session->wtpctrladdress : &session->wtpdataaddress), sizeof(struct sockaddr_storage)); - - if (isctrlsocket) { - if (!capwap_recv_retrasmitted_request(&session->ctrldtls, rxmngpacket, &connection, session->lastrecvpackethash, session->responsefragmentpacket)) { - /* Check message type */ - res = capwap_check_message_type(rxmngpacket); - if (res != VALID_MESSAGE_TYPE) { - if (res == INVALID_REQUEST_MESSAGE_TYPE) { - capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error"); - ac_send_invalid_request(session, rxmngpacket, &connection, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST); - } - - ignorepacket = 1; - capwap_logging_debug("Invalid message type"); - } - } else { - ignorepacket = 1; - capwap_logging_debug("Retrasmitted packet"); + /* Receive all fragment */ + if (!capwap_recv_retrasmitted_request(&session->dtls, session->rxmngpacket, &session->connection, session->lastrecvpackethash, session->responsefragmentpacket)) { + /* Check message type */ + res = capwap_check_message_type(session->rxmngpacket); + if (res != VALID_MESSAGE_TYPE) { + if (res == INVALID_REQUEST_MESSAGE_TYPE) { + capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error"); + ac_send_invalid_request(session, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST); } + + ignorepacket = 1; + capwap_logging_debug("Invalid message type"); } + } else { + ignorepacket = 1; + capwap_logging_debug("Retrasmitted packet"); + } - /* Parsing packet */ - if (!ignorepacket) { - res = capwap_parsing_packet(rxmngpacket, &connection, &packet); - if (res == PARSING_COMPLETE) { - /* Validate packet */ - if (capwap_validate_parsed_packet(&packet, NULL)) { - if (isctrlsocket && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) { - capwap_logging_warning("Missing Mandatory Message Element, send Response Packet with error"); - ac_send_invalid_request(session, rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT); - } - - ignorepacket = 1; - capwap_logging_debug("Failed validation parsed packet"); - } - } else { - if (isctrlsocket && (res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) { - capwap_logging_warning("Unrecognized Message Element, send Response Packet with error"); - ac_send_invalid_request(session, rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT); - /* TODO: add the unrecognized message element */ + /* Parsing packet */ + if (!ignorepacket) { + res = capwap_parsing_packet(session->rxmngpacket, &session->connection, &packet); + if (res == PARSING_COMPLETE) { + /* Validate packet */ + if (capwap_validate_parsed_packet(&packet, NULL)) { + if (capwap_is_request_type(session->rxmngpacket->ctrlmsg.type)) { + capwap_logging_warning("Missing Mandatory Message Element, send Response Packet with error"); + ac_send_invalid_request(session, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT); } ignorepacket = 1; - capwap_logging_debug("Failed parsing packet"); + capwap_logging_debug("Failed validation parsed packet"); + } + } else { + if ((res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(session->rxmngpacket->ctrlmsg.type)) { + capwap_logging_warning("Unrecognized Message Element, send Response Packet with error"); + ac_send_invalid_request(session, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT); + /* TODO: add the unrecognized message element */ } - } - /* */ - if (!ignorepacket) { - ac_dfa_execute(session, &packet); + ignorepacket = 1; + capwap_logging_debug("Failed parsing packet"); } + } - /* Free memory */ - capwap_free_parsed_packet(&packet); - ac_free_packet_rxmng(session, isctrlsocket); - } else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) { - /* Discard fragments */ - ac_free_packet_rxmng(session, isctrlsocket); + /* */ + if (!ignorepacket) { + ac_dfa_execute(session, &packet); + } + + /* Free memory */ + capwap_free_parsed_packet(&packet); + if (session->rxmngpacket) { + capwap_packet_rxmng_free(session->rxmngpacket); + session->rxmngpacket = NULL; + } + } else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) { + /* Discard fragments */ + if (session->rxmngpacket) { + capwap_packet_rxmng_free(session->rxmngpacket); + session->rxmngpacket = NULL; } } } @@ -483,18 +495,13 @@ void ac_session_teardown(struct ac_session_t* session) { capwap_rwlock_exit(&g_ac.sessionslock); /* Remove all pending packets */ - while ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) { - capwap_itemlist_free(capwap_itemlist_remove_head(((session->controlpackets->count > 0) ? session->controlpackets : session->datapackets))); + while (session->packets->count > 0) { + capwap_itemlist_free(capwap_itemlist_remove_head(session->packets)); } /* Close DTSL Control */ - if (session->ctrldtls.enable) { - capwap_crypt_close(&session->ctrldtls); - } - - /* Close DTLS Data */ - if (session->datadtls.enable) { - capwap_crypt_close(&session->datadtls); + if (session->dtls.enable) { + capwap_crypt_close(&session->dtls); } /* */ @@ -566,7 +573,7 @@ void ac_get_control_information(struct capwap_list* controllist) { for (search = g_ac.sessions->first; search != NULL; search = search->next) { struct ac_session_t* session = (struct ac_session_t*)search->item; - if (!capwap_compare_ip(&session->acctrladdress, &sessioncontrol->localaddress)) { + if (!capwap_compare_ip(&session->connection.localaddr, &sessioncontrol->localaddress)) { sessioncontrol->count++; } } diff --git a/src/ac/ac_session.h b/src/ac/ac_session.h index b440ef0..0aef48f 100644 --- a/src/ac/ac_session.h +++ b/src/ac/ac_session.h @@ -19,7 +19,8 @@ struct ac_session_control { }; /* */ -#define AC_SESSION_ACTION_RESET_WTP 1 +#define AC_SESSION_ACTION_RESET_WTP 1 +#define AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA 2 /* */ struct ac_session_action { @@ -29,75 +30,102 @@ struct ac_session_action { char data[0]; }; +/* */ +struct ac_session_t; +struct ac_session_data_t; + +/* AC sessions data */ +struct ac_session_data_t { + int running; + pthread_t threadid; + struct capwap_list_item* itemlist; /* My itemlist into g_ac.sessionsdata */ + + /* Reference */ + long count; + capwap_event_t changereference; + + int enabledtls; + unsigned short mtu; + struct capwap_connection connection; + struct capwap_dtls dtls; + struct timeout_control timeout; + + capwap_event_t waitpacket; + capwap_lock_t sessionlock; + struct capwap_list* action; + struct capwap_list* packets; + + struct capwap_packet_rxmng* rxmngpacket; + + struct ac_session_t* session; + struct capwap_sessionid_element sessionid; +}; + /* AC sessions */ struct ac_session_t { + int running; + pthread_t threadid; struct capwap_list_item* itemlist; /* My itemlist into g_ac.sessions */ - struct ac_state dfa; + + /* Reference */ + long count; + capwap_event_t changereference; /* Soap */ struct ac_http_soap_request* soaprequest; /* */ char* wtpid; - int running; + unsigned long state; + struct ac_state dfa; int waitresponse; - unsigned long count; - struct sockaddr_storage acctrladdress; - struct sockaddr_storage acdataaddress; - struct sockaddr_storage wtpctrladdress; - struct sockaddr_storage wtpdataaddress; - struct capwap_socket ctrlsocket; - struct capwap_socket datasocket; - struct timeout_control timeout; - - struct capwap_sessionid_element sessionid; unsigned short binding; + struct ac_session_data_t* sessiondata; + struct capwap_sessionid_element sessionid; int teardown; - struct capwap_dtls ctrldtls; - struct capwap_dtls datadtls; - - pthread_t threadid; + unsigned short mtu; + struct capwap_dtls dtls; + struct capwap_connection connection; + struct timeout_control timeout; capwap_event_t waitpacket; capwap_lock_t sessionlock; - struct capwap_list* actionsession; - struct capwap_list* controlpackets; - struct capwap_list* datapackets; + struct capwap_list* action; + struct capwap_list* packets; unsigned char localseqnumber; unsigned char remoteseqnumber; - unsigned short mtu; unsigned short fragmentid; - struct capwap_packet_rxmng* rxmngctrlpacket; - struct capwap_packet_rxmng* rxmngdatapacket; + struct capwap_packet_rxmng* rxmngpacket; struct capwap_list* requestfragmentpacket; struct capwap_list* responsefragmentpacket; unsigned char lastrecvpackethash[16]; - - unsigned long state; }; -/* */ +/* Session */ void* ac_session_thread(void* param); void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length); +void ac_session_reset(struct ac_session_t* session, struct capwap_imageidentifier_element* startupimage); +void ac_session_teardown(struct ac_session_t* session); +void ac_session_close(struct ac_session_t* session); +void ac_session_release_reference(struct ac_session_t* session); + +/* Session data */ +void* ac_session_data_thread(void* param); +void ac_session_data_close(struct ac_session_data_t* sessiondata); +void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length); +void ac_session_data_release_reference(struct ac_session_data_t* sessiondata); /* */ int ac_has_sessionid(struct capwap_sessionid_element* sessionid); -struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid); int ac_has_wtpid(const char* wtpid); struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid); /* */ char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata); -/* */ -void ac_session_reset(struct ac_session_t* session, struct capwap_imageidentifier_element* startupimage); -void ac_session_teardown(struct ac_session_t* session); -void ac_session_close(struct ac_session_t* session); -void ac_session_release_reference(struct ac_session_t* session); - /* */ void ac_dfa_change_state(struct ac_session_t* session, int state); @@ -114,8 +142,8 @@ void ac_session_msgqueue_free(void); void ac_session_msgqueue_notify_closethread(pthread_t threadid); /* */ -int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param); int ac_dtls_setup(struct ac_session_t* session); +int ac_dtls_data_setup(struct ac_session_data_t* sessiondata); /* */ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet); diff --git a/src/ac/ac_session_data.c b/src/ac/ac_session_data.c new file mode 100644 index 0000000..b8d0a4d --- /dev/null +++ b/src/ac/ac_session_data.c @@ -0,0 +1,393 @@ +#include "ac.h" +#include "capwap_dfa.h" +#include "ac_session.h" +#include + +#define AC_ERROR_TIMEOUT -1000 +#define AC_ERROR_ACTION_SESSION -1001 + +/* */ +static int ac_session_data_action_execute(struct ac_session_data_t* sessiondata, struct ac_session_action* action) { + int result = AC_ERROR_ACTION_SESSION; + + /* TODO */ + + return result; +} + +/* */ +static int ac_network_read(struct ac_session_data_t* sessiondata, void* buffer, int length, struct timeout_control* timeout) { + long indextimer; + long waittimeout; + int result = CAPWAP_ERROR_AGAIN; + + ASSERT(sessiondata != NULL); + ASSERT(buffer != NULL); + ASSERT(length > 0); + + for (;;) { + capwap_lock_enter(&sessiondata->sessionlock); + + if (!sessiondata->running) { + capwap_lock_exit(&sessiondata->sessionlock); + return CAPWAP_ERROR_CLOSE; + } else if (sessiondata->action->count > 0) { + struct capwap_list_item* itemaction; + + itemaction = capwap_itemlist_remove_head(sessiondata->action); + capwap_lock_exit(&sessiondata->sessionlock); + + /* */ + result = ac_session_data_action_execute(sessiondata, (struct ac_session_action*)itemaction->item); + + /* Free packet */ + capwap_itemlist_free(itemaction); + return result; + } else if (sessiondata->packets->count > 0) { + struct capwap_list_item* itempacket; + + capwap_logging_debug("Receive data packet"); + + /* Get packet */ + itempacket = capwap_itemlist_remove_head(sessiondata->packets); + capwap_lock_exit(&sessiondata->sessionlock); + + if (itempacket) { + struct ac_packet* packet = (struct ac_packet*)itempacket->item; + long packetlength = itempacket->itemsize - sizeof(struct ac_packet); + + if (!packet->plainbuffer && sessiondata->dtls.enable) { + result = capwap_decrypt_packet(&sessiondata->dtls, packet->buffer, packetlength, buffer, length); + } else { + if (packetlength <= length) { + memcpy(buffer, packet->buffer, packetlength); + result = packetlength; + } + } + + /* Free packet */ + capwap_itemlist_free(itempacket); + } + + return result; + } + + capwap_lock_exit(&sessiondata->sessionlock); + + /* Update timeout */ + capwap_update_timeout(timeout); + waittimeout = capwap_get_timeout(timeout, &indextimer); + if ((waittimeout <= 0) && (indextimer != CAPWAP_TIMER_UNDEF)) { + return AC_ERROR_TIMEOUT; + } + + /* Wait packet */ + capwap_event_wait_timeout(&sessiondata->waitpacket, waittimeout); + } + + return result; +} + +/* Management keep-alive */ +static int ac_session_data_keepalive(struct ac_session_data_t* sessiondata, struct capwap_parsed_packet* packet) { + int result = 0; + struct capwap_list* txfragpacket; + struct capwap_header_data capwapheader; + struct capwap_packet_txmng* txmngpacket; + struct capwap_sessionid_element* sessionid; + + /* Get session id */ + sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID); + if (!sessionid) { + return 0; + } + + /* */ + if (sessiondata->session) { + if (memcmp(sessionid, &sessiondata->sessionid, sizeof(struct capwap_sessionid_element))) { + return 0; /* Invalid session id */ + } + } else { + struct capwap_list_item* search; + + /* Retrieve session and interconnect with session data */ + capwap_rwlock_rdlock(&g_ac.sessionslock); + + search = g_ac.sessions->first; + while (search != NULL) { + struct ac_session_t* session = (struct ac_session_t*)search->item; + ASSERT(session != NULL); + + if (!memcmp(sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) { + /* Link session and session data */ + capwap_lock_enter(&session->sessionlock); + session->count++; + sessiondata->session = session; + capwap_event_signal(&session->changereference); + capwap_lock_exit(&session->sessionlock); + + capwap_lock_enter(&sessiondata->sessionlock); + sessiondata->count++; + session->sessiondata = sessiondata; + capwap_event_signal(&sessiondata->changereference); + capwap_lock_exit(&sessiondata->sessionlock); + + break; + } + + search = search->next; + } + + capwap_rwlock_exit(&g_ac.sessionslock); + + /* */ + if (sessiondata->session) { +#ifdef DEBUG + char sessionname[33]; + + capwap_sessionid_printf(sessionid, sessionname); + capwap_logging_debug("Establiched Session Data AC %s", sessionname); +#endif + + /* Notify established session data */ + memcpy(&sessiondata->sessionid, sessionid, sizeof(struct capwap_sessionid_element)); + ac_session_send_action(sessiondata->session, AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA, 0, NULL, 0); + } else { + return 0; /* Session not found */ + } + } + + /* Send keep-alive response */ + capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(packet->rxmngpacket->header)); + capwap_header_set_keepalive_flag(&capwapheader, 1); + txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, sessiondata->mtu); + + /* Add message element */ + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &sessiondata->sessionid); + + /* Data keepalive complete, get fragment packets into local list */ + txfragpacket = capwap_list_create(); + capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0); + if (txfragpacket->count == 1) { + /* Send Data keepalive to WTP */ + if (capwap_crypt_sendto_fragmentpacket(&sessiondata->dtls, sessiondata->connection.socket.socket[sessiondata->connection.socket.type], txfragpacket, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr)) { + result = 1; + } else { + capwap_logging_debug("Warning: error to send data channel keepalive packet"); + } + } else { + capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet"); + } + + /* Free packets manager */ + capwap_list_free(txfragpacket); + capwap_packet_txmng_free(txmngpacket); + return result; +} + +/* Release reference of session data */ +static void ac_session_data_destroy(struct ac_session_data_t* sessiondata) { +#ifdef DEBUG + char sessionname[33]; +#endif + + ASSERT(sessiondata != NULL); + +#ifdef DEBUG + capwap_sessionid_printf(&sessiondata->sessionid, sessionname); + capwap_logging_debug("Release Session Data AC %s", sessionname); +#endif + + /* Remove session data from list */ + capwap_rwlock_wrlock(&g_ac.sessionslock); + capwap_itemlist_remove(g_ac.sessionsdata, sessiondata->itemlist); + capwap_rwlock_exit(&g_ac.sessionslock); + + /* Release session reference */ + if (sessiondata->session) { + ac_session_close(sessiondata->session); + ac_session_release_reference(sessiondata->session); + } + + /* Release last reference */ + capwap_lock_enter(&sessiondata->sessionlock); + sessiondata->count--; + + /* Check if all reference is release */ + while (sessiondata->count > 0) { +#ifdef DEBUG + capwap_logging_debug("Wait for release Session Data AC %s (count=%d)", sessionname, sessiondata->count); +#endif + /* */ + capwap_event_reset(&sessiondata->changereference); + capwap_lock_exit(&sessiondata->sessionlock); + + /* Wait */ + capwap_event_wait(&sessiondata->changereference); + + capwap_lock_enter(&sessiondata->sessionlock); + } + + capwap_lock_exit(&sessiondata->sessionlock); + + /* Free DTLS */ + capwap_crypt_freesession(&sessiondata->dtls); + + /* Free resource */ + while (sessiondata->packets->count > 0) { + capwap_itemlist_free(capwap_itemlist_remove_head(sessiondata->packets)); + } + + /* */ + capwap_event_destroy(&sessiondata->changereference); + capwap_event_destroy(&sessiondata->waitpacket); + capwap_lock_destroy(&sessiondata->sessionlock); + capwap_list_free(sessiondata->action); + capwap_list_free(sessiondata->packets); + + /* Free fragments packet */ + if (sessiondata->rxmngpacket) { + capwap_packet_rxmng_free(sessiondata->rxmngpacket); + } + + /* Free item */ + capwap_itemlist_free(sessiondata->itemlist); +} + +/* */ +static void ac_session_data_report_connection(struct ac_session_data_t* sessiondata) { + char localip[INET6_ADDRSTRLEN + 10] = ""; + char remoteip[INET6_ADDRSTRLEN + 10] = ""; + + if (sessiondata->connection.localaddr.ss_family == AF_INET) { + char buffer[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_port)); + } else if (sessiondata->connection.localaddr.ss_family == AF_INET6) { + char buffer[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_port)); + } + + if (sessiondata->connection.remoteaddr.ss_family == AF_INET) { + char buffer[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN); + sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_port)); + } else if (sessiondata->connection.remoteaddr.ss_family == AF_INET6) { + char buffer[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN); + sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_port)); + } + + capwap_logging_info("Start data channel from %s to %s", remoteip, localip); +} + +/* */ +static void ac_session_data_run(struct ac_session_data_t* sessiondata) { + int res; + int check; + int length; + struct capwap_connection connection; + char buffer[CAPWAP_MAX_PACKET_SIZE]; + + ASSERT(sessiondata != NULL); + + /* */ + ac_session_data_report_connection(sessiondata); + + /* Create DTLS channel */ + if (sessiondata->enabledtls) { + if (!ac_dtls_data_setup(sessiondata)) { + capwap_logging_debug("Unable to start DTLS data"); + sessiondata->running = 0; + } + } + + /* */ + //capwap_set_timeout(0, &sessiondata->timeout, CAPWAP_TIMER_DATA_KEEPALIVEDEAD); + + while (sessiondata->running) { + /* Get packet */ + length = ac_network_read(sessiondata, buffer, sizeof(buffer), &sessiondata->timeout); + if (length < 0) { + if ((length == AC_ERROR_ACTION_SESSION) || (length == CAPWAP_ERROR_AGAIN)) { + continue; /* Nothing */ + } + + break; /* Close Session Data */ + } else if (length > 0) { + /* Check generic capwap packet */ + check = capwap_sanity_check(0, CAPWAP_UNDEF_STATE, buffer, length, 0, 0); + if (check == CAPWAP_PLAIN_PACKET) { + struct capwap_parsed_packet packet; + + /* Defragment management */ + if (!sessiondata->rxmngpacket) { + sessiondata->rxmngpacket = capwap_packet_rxmng_create_message(0); + } + + /* If request, defragmentation packet */ + check = capwap_packet_rxmng_add_recv_packet(sessiondata->rxmngpacket, buffer, length); + if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) { + /* Validate message */ + if (capwap_check_message_type(sessiondata->rxmngpacket) == VALID_MESSAGE_TYPE) { + /* Parsing packet */ + res = capwap_parsing_packet(sessiondata->rxmngpacket, &connection, &packet); + if (res == PARSING_COMPLETE) { + /* Validate packet */ + if (!capwap_validate_parsed_packet(&packet, NULL)) { + if (IS_FLAG_K_HEADER(packet.rxmngpacket->header)) { + ac_session_data_keepalive(sessiondata, &packet); + } else { + /* TODO */ + } + } else { + capwap_logging_debug("Failed validation parsed packet"); + } + } else { + capwap_logging_debug("Failed parsing packet"); + } + } + + /* Free memory */ + capwap_free_parsed_packet(&packet); + capwap_packet_rxmng_free(sessiondata->rxmngpacket); + sessiondata->rxmngpacket = NULL; + } else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) { + /* Discard fragments */ + capwap_packet_rxmng_free(sessiondata->rxmngpacket); + sessiondata->rxmngpacket = NULL; + } + } + } + } + + /* Release reference session data */ + ac_session_data_destroy(sessiondata); +} + +/* */ +void* ac_session_data_thread(void* param) { + pthread_t threadid; + struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param; + + ASSERT(param != NULL); + + threadid = sessiondata->threadid; + + /* */ + capwap_logging_debug("Session data start"); + ac_session_data_run(sessiondata); + capwap_logging_debug("Session data end"); + + /* Notify terminate thread */ + ac_session_msgqueue_notify_closethread(threadid); + + /* Thread exit */ + pthread_exit(NULL); + return NULL; +}