/* Change WTP state machine */ void ac_dfa_change_state(struct ac_session_t* session, int state) { struct capwap_list_item* search; ASSERT(session != NULL); if (state != session->state) { #ifdef DEBUG char sessionname[33]; capwap_sessionid_printf(&session->sessionid, sessionname); capwap_logging_debug("Session AC %s change state from %s to %s", sessionname, capwap_dfa_getname(session->state), capwap_dfa_getname(state)); #endif session->state = state; /* Search into notify event */ search = session->notifyevent->first; while (search != NULL) { struct ac_session_notify_event_t* notify = (struct ac_session_notify_event_t*)search->item; if ((notify->action == NOTIFY_ACTION_CHANGE_STATE) && (notify->session_state == state)) { char buffer[4]; struct ac_soap_response* response; /* */ response = ac_soap_updatebackendevent(session, notify->idevent, capwap_itoa(SOAP_EVENT_STATUS_COMPLETE, buffer)); if (response) { ac_soapclient_free_response(response); } /* Remove notify event */ capwap_itemlist_free(capwap_itemlist_remove(session->notifyevent, search)); break; } search = search->next; } } }
static int ac_session_action_execute(struct ac_session_t* session, struct ac_session_action* action) { int result = AC_NO_ERROR; switch (action->action) { case AC_SESSION_ACTION_CLOSE: { result = CAPWAP_ERROR_CLOSE; break; } case AC_SESSION_ACTION_RESET_WTP: { result = ac_session_action_resetwtp(session, (struct ac_notify_reset_t*)action->data); break; } case AC_SESSION_ACTION_ADDWLAN: { result = ac_session_action_addwlan(session, (struct ac_notify_addwlan_t*)action->data); break; } case AC_SESSION_ACTION_RECV_KEEPALIVE: { #ifdef DEBUG { char sessionname[33]; capwap_sessionid_printf(&session->sessionid, sessionname); capwap_logging_debug("Receive Keep-Alive from %s", sessionname); } #endif /* Send keep-alive response */ //ac_kmod_send_keepalive(&session->sessionid); capwap_timeout_set(session->timeout, session->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, ac_dfa_teardown_timeout, session, NULL); /* */ if (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) { struct ac_soap_response* response; /* Capwap handshake complete, notify event to backend */ response = ac_soap_runningwtpsession(session, session->wtpid); if (response) { if (response->responsecode == HTTP_RESULT_OK) { ac_dfa_change_state(session, CAPWAP_RUN_STATE); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL); } else { result = CAPWAP_ERROR_CLOSE; } ac_soapclient_free_response(response); } else { result = CAPWAP_ERROR_CLOSE; } } break; } case AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET: { result = ac_session_action_recv_ieee80211_mgmt_packet(session, (struct capwap_header*)action->data, action->length); break; } case AC_SESSION_ACTION_NOTIFY_EVENT: { struct capwap_list_item* item; /* Copy event into queue */ item = capwap_itemlist_create(sizeof(struct ac_session_notify_event_t)); memcpy(item->item, action->data, sizeof(struct ac_session_notify_event_t)); capwap_itemlist_insert_after(session->notifyevent, NULL, item); break; } case AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION: { result = ac_session_action_station_configuration_ieee8011_add_station(session, (struct ac_notify_station_configuration_ieee8011_add_station*)action->data); break; } case AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION: { result = ac_session_action_station_configuration_ieee8011_delete_station(session, (struct ac_notify_station_configuration_ieee8011_delete_station*)action->data); break; } case AC_SESSION_ACTION_STATION_ROAMING: { struct ac_station* station; /* Delete station */ station = ac_stations_get_station(session, RADIOID_ANY, NULL, (uint8_t*)action->data); if (station) { ac_stations_delete_station(session, station); } break; } } return result; }
/* Release reference of session */ static void ac_session_destroy(struct ac_session_t* session) { #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 last reference */ capwap_lock_enter(&session->sessionlock); session->count--; /* Terminate SOAP request pending */ if (session->soaprequest) { ac_soapclient_shutdown_request(session->soaprequest); } /* Check if all reference is release */ while (session->count > 0) { #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_event_wait(&session->changereference); capwap_lock_enter(&session->sessionlock); } capwap_lock_exit(&session->sessionlock); /* Close data channel */ ac_kmod_delete_datasession(&session->sessionid); /* Free DTSL Control */ capwap_crypt_freesession(&session->dtls); /* Free resource */ while (session->packets->count > 0) { capwap_itemlist_free(capwap_itemlist_remove_head(session->packets)); } /* Free WLANS */ ac_wlans_destroy(session); /* */ capwap_event_destroy(&session->changereference); capwap_event_destroy(&session->waitpacket); capwap_lock_destroy(&session->sessionlock); capwap_list_free(session->action); capwap_list_free(session->packets); /* Free fragments packet */ if (session->rxmngpacket) { capwap_packet_rxmng_free(session->rxmngpacket); } capwap_list_free(session->requestfragmentpacket); capwap_list_free(session->responsefragmentpacket); capwap_list_free(session->notifyevent); capwap_timeout_free(session->timeout); /* Free DFA resource */ capwap_array_free(session->dfa.acipv4list.addresses); capwap_array_free(session->dfa.acipv6list.addresses); if (session->wtpid) { capwap_free(session->wtpid); } /* Free item */ capwap_itemlist_free(session->itemlist); }
void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet) { unsigned short binding; struct ac_soap_response* response; struct capwap_header_data capwapheader; struct capwap_packet_txmng* txmngpacket; struct capwap_sessionid_element* sessionid; struct capwap_wtpboarddata_element* wtpboarddata; struct capwap_resultcode_element resultcode = { .code = CAPWAP_RESULTCODE_FAILURE }; ASSERT(session != NULL); ASSERT(packet != NULL); /* Check binding */ binding = GET_WBID_HEADER(packet->rxmngpacket->header); if (ac_valid_binding(binding)) { if (packet->rxmngpacket->ctrlmsg.type == CAPWAP_JOIN_REQUEST) { /* Get sessionid and verify unique id */ sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID); if (!ac_has_sessionid(sessionid)) { char* wtpid; /* Checking macaddress for detect if WTP already connected */ wtpboarddata = (struct capwap_wtpboarddata_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_WTPBOARDDATA); /* Get printable WTPID */ wtpid = ac_get_printable_wtpid(wtpboarddata); if (wtpid && !ac_has_wtpid(wtpid)) { /* Request authorization of Backend for complete join */ response = ac_soap_authorizewtpsession(session, wtpid); if (response) { resultcode.code = ac_dfa_state_join_check_authorizejoin(session, response); ac_soapclient_free_response(response); } else { resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE; } } else { capwap_logging_info("WTP Id %s already used in another session", wtpid); resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE; } /* */ if (CAPWAP_RESULTCODE_OK(resultcode.code)) { session->wtpid = wtpid; memcpy(&session->sessionid, sessionid, sizeof(struct capwap_sessionid_element)); session->binding = binding; } else if (wtpid) { capwap_free(wtpid); } } else { char sessionname[33]; capwap_sessionid_printf(sessionid, sessionname); capwap_logging_info("Session Id %s already used in another session", sessionname); resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_ID_ALREADY_IN_USE; } } else { resultcode.code = CAPWAP_RESULTCODE_MSG_UNEXPECTED_INVALID_CURRENT_STATE; } } else { resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_BINDING_NOT_SUPPORTED; } /* Create response */ capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, binding); txmngpacket = capwap_packet_txmng_create_ctrl_message(&capwapheader, CAPWAP_JOIN_RESPONSE, packet->rxmngpacket->ctrlmsg.seq, session->mtu); /* */ if (CAPWAP_RESULTCODE_OK(resultcode.code)) { response = ac_dfa_state_join_parsing_request(session, packet); if (response) { resultcode.code = ac_dfa_state_join_create_response(session, packet, response, txmngpacket); ac_soapclient_free_response(response); } } /* Add always result code message element */ capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RESULTCODE, &resultcode); /* Join response complete, get fragment packets */ ac_free_reference_last_response(session); capwap_packet_txmng_get_fragment_packets(txmngpacket, session->responsefragmentpacket, session->fragmentid); if (session->responsefragmentpacket->count > 1) { session->fragmentid++; } /* Free packets manager */ capwap_packet_txmng_free(txmngpacket); /* Save remote sequence number */ session->remotetype = packet->rxmngpacket->ctrlmsg.type; session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; /* Send Join response to WTP */ if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) { if (CAPWAP_RESULTCODE_OK(resultcode.code)) { ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL); } else { ac_session_teardown(session); } } else { /* Error to send packets */ capwap_logging_debug("Warning: error to send join response packet"); ac_session_teardown(session); } }