From 539fa51e6917bd297939ce4e5fdd01ab35505d02 Mon Sep 17 00:00:00 2001 From: vemax78 Date: Sun, 6 Apr 2014 17:02:31 +0200 Subject: [PATCH] Fix functions and logic. Add new functions Add logic into AC for create/destroy station --- src/ac/ac.c | 3 +- src/ac/ac_80211_json_wtpradioconf.c | 2 +- src/ac/ac_dfa_run.c | 6 +- src/ac/ac_execute.c | 60 +++++-- src/ac/ac_ieee80211_data.c | 122 ++++++++----- src/ac/ac_session.c | 10 +- src/ac/ac_session.h | 6 +- src/ac/ac_session_data.c | 4 +- src/ac/ac_wlans.c | 256 +++++++++++++++++++++++---- src/ac/ac_wlans.h | 39 ++-- src/binding/ieee80211/wifi_nl80211.c | 68 ++++--- src/common/capwap_element.c | 6 +- src/common/capwap_hash.c | 33 ++-- src/common/capwap_hash.h | 7 +- src/common/capwap_network.h | 4 + src/common/capwap_rfc.h | 4 +- src/common/capwap_timeout.c | 18 ++ 17 files changed, 482 insertions(+), 166 deletions(-) diff --git a/src/ac/ac.c b/src/ac/ac.c index 44f7e46..e04d59c 100644 --- a/src/ac/ac.c +++ b/src/ac/ac.c @@ -21,7 +21,7 @@ static char g_configurationfile[260] = AC_DEFAULT_CONFIGURATION_FILE; static unsigned long ac_stations_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; - ASSERT(keysize == ETH_ALEN); + ASSERT(keysize == MACADDRESS_EUI48_LENGTH); return ((((unsigned long)macaddress[4] << 8) | (unsigned long)macaddress[5]) ^ ((unsigned long)macaddress[3] << 4)); } @@ -116,6 +116,7 @@ static void ac_destroy(void) { ac_msgqueue_free(); /* Stations */ + ASSERT(g_ac.stations->count == 0); capwap_hash_free(g_ac.stations); capwap_rwlock_destroy(&g_ac.stationslock); diff --git a/src/ac/ac_80211_json_wtpradioconf.c b/src/ac/ac_80211_json_wtpradioconf.c index 0da66d7..9a04f26 100644 --- a/src/ac/ac_80211_json_wtpradioconf.c +++ b/src/ac/ac_80211_json_wtpradioconf.c @@ -104,7 +104,7 @@ static int ac_json_80211_wtpradioconf_addmessageelement(struct ac_json_ieee80211 /* */ static void ac_json_80211_wtpradioconf_createjson(struct json_object* jsonparent, void* data) { - char buffer[18]; + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; struct json_object* jsonitem; struct capwap_80211_wtpradioconf_element* wtpradioconf = (struct capwap_80211_wtpradioconf_element*)data; diff --git a/src/ac/ac_dfa_run.c b/src/ac/ac_dfa_run.c index 1b8690f..7e68dcc 100644 --- a/src/ac/ac_dfa_run.c +++ b/src/ac/ac_dfa_run.c @@ -65,15 +65,15 @@ static int receive_echo_request(struct ac_session_t* session, struct capwap_pars /* */ static void execute_ieee80211_wlan_configuration_addwlan(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_80211_addwlan_element* addwlan, struct capwap_parsed_packet* requestpacket) { - char buffer[18]; + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; struct ac_wlan* wlan; struct capwap_80211_assignbssid_element* assignbssid; /* Get BSSID */ assignbssid = (struct capwap_80211_assignbssid_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_ASSIGN_BSSID); if (assignbssid && (assignbssid->radioid == addwlan->radioid) && (assignbssid->wlanid == addwlan->wlanid)) { - if (!ac_wlans_get_bssid(session->wlans, assignbssid->radioid, assignbssid->bssid)) { - wlan = ac_wlans_create_bssid(session->wlans, assignbssid->radioid, assignbssid->wlanid, assignbssid->bssid); + if (!ac_wlans_get_bssid(session, assignbssid->radioid, assignbssid->bssid)) { + wlan = ac_wlans_create_bssid(session, assignbssid->radioid, assignbssid->wlanid, assignbssid->bssid); wlan->session = session; wlan->sessiondata = session->sessiondata; diff --git a/src/ac/ac_execute.c b/src/ac/ac_execute.c index c397c19..6980988 100644 --- a/src/ac/ac_execute.c +++ b/src/ac/ac_execute.c @@ -185,9 +185,10 @@ static void ac_session_data_add_packet(struct ac_session_data_t* sessiondata, ch } /* Add action to session */ -void ac_session_send_action(struct ac_session_t* session, long action, long param, void* data, long length) { +void ac_session_send_action(struct ac_session_t* session, long action, long param, const void* data, long length) { struct capwap_list_item* item; struct ac_session_action* actionsession; + struct capwap_list_item* search; ASSERT(session != NULL); ASSERT(length >= 0); @@ -203,17 +204,33 @@ void ac_session_send_action(struct ac_session_t* session, long action, long para memcpy(actionsession->data, data, length); } - /* Append to actions list */ - capwap_lock_enter(&session->sessionlock); - capwap_itemlist_insert_after(session->action, NULL, item); - capwap_event_signal(&session->waitpacket); - capwap_lock_exit(&session->sessionlock); + /* Validate session before use */ + capwap_rwlock_rdlock(&g_ac.sessionslock); + + search = g_ac.sessions->first; + while (search != NULL) { + if (session == (struct ac_session_t*)search->item) { + /* Append to actions list */ + capwap_lock_enter(&session->sessionlock); + capwap_itemlist_insert_after(session->action, NULL, item); + capwap_event_signal(&session->waitpacket); + capwap_lock_exit(&session->sessionlock); + + break; + } + + /* */ + search = search->next; + } + + capwap_rwlock_exit(&g_ac.sessionslock); } /* 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; + struct capwap_list_item* search; ASSERT(sessiondata != NULL); ASSERT(length >= 0); @@ -229,11 +246,28 @@ void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long act 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); + /* Validate session data before use */ + capwap_rwlock_rdlock(&g_ac.sessionslock); + + search = g_ac.sessionsdata->first; + while (search != NULL) { + struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item; + + if (sessiondata == (struct ac_session_data_t*)search->item) { + /* 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); + + break; + } + + /* */ + search = search->next; + } + + capwap_rwlock_exit(&g_ac.sessionslock); } /* Find AC sessions */ @@ -406,7 +440,7 @@ char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata) { /* Get macaddress */ wtpboarddatamacaddress = capwap_wtpboarddata_get_subelement(wtpboarddata, CAPWAP_BOARD_SUBELEMENT_MACADDRESS); if (wtpboarddatamacaddress != NULL) { - wtpid = capwap_alloc(((wtpboarddatamacaddress->length == MACADDRESS_EUI48_LENGTH) ? 18 : 24)); + wtpid = capwap_alloc(((wtpboarddatamacaddress->length == MACADDRESS_EUI48_LENGTH) ? CAPWAP_MACADDRESS_EUI48_BUFFER : CAPWAP_MACADDRESS_EUI64_BUFFER)); capwap_printf_macaddress(wtpid, (unsigned char*)wtpboarddatamacaddress->data, wtpboarddatamacaddress->length); } @@ -503,7 +537,7 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres capwap_event_init(&session->changereference); /* */ - session->wlans = ac_wlans_init(); + ac_wlans_init(session); /* */ session->timeout = capwap_timeout_init(); diff --git a/src/ac/ac_ieee80211_data.c b/src/ac/ac_ieee80211_data.c index 00dcdbb..62707e9 100644 --- a/src/ac/ac_ieee80211_data.c +++ b/src/ac/ac_ieee80211_data.c @@ -1,9 +1,9 @@ #include "ac.h" #include "ac_session.h" -#include "ieee80211.h" +#include "ac_wlans.h" /* */ -static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { +static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; struct ieee80211_ie_items ieitems; @@ -17,13 +17,59 @@ static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* ses } /* */ -static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { +static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + struct ac_station* station; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { + return; + } + + /* Create station */ + station = ac_stations_create_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa); + + /* */ + if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + /* TODO */ + } else if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + /* TODO */ + } +} + +/* */ +static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + struct ac_station* station; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { + return; + } + + /* Get station */ + station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa); + + /* */ + if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + /* TODO */ + } else if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + /* TODO */ + } +} + +/* */ +static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; struct ieee80211_ie_items ieitems; /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->reassociationrequest.ie[0], ielength)) { return; } @@ -31,13 +77,13 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se } /* */ -static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { +static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; struct ieee80211_ie_items ieitems; /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->disassociation.ie[0], ielength)) { return; } @@ -45,53 +91,30 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_ } /* */ -static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { +static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; + const uint8_t* stationaddress; struct ieee80211_ie_items ieitems; /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->deauthetication.ie[0], ielength)) { return; } - /* TODO */ + /* Get station address */ + stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da); + + /* Delete station */ + ac_stations_delete_station(sessiondata->session, stationaddress); } /* */ -static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) { +static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) { switch (framecontrol_subtype) { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) { - ac_ieee80211_mgmt_probe_request_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_probe_request_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -99,7 +122,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) { - ac_ieee80211_mgmt_authentication_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_authentication_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -107,7 +130,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) { - ac_ieee80211_mgmt_association_request_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_association_request_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -115,7 +138,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) { - ac_ieee80211_mgmt_reassociation_request_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_reassociation_request_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -123,7 +146,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) { - ac_ieee80211_mgmt_disassociation_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_disassociation_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -131,7 +154,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) { - ac_ieee80211_mgmt_deauthentication_packet(sessiondata, mgmt, mgmtlength); + ac_ieee80211_mgmt_deauthentication_packet(sessiondata, radioid, mgmt, mgmtlength); } break; @@ -144,13 +167,14 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, cons } /* */ -void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, const uint8_t* buffer, int length) { +void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const uint8_t* buffer, int length) { const struct ieee80211_header* header; uint16_t framecontrol; uint16_t framecontrol_type; uint16_t framecontrol_subtype; ASSERT(sessiondata != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(buffer != NULL); ASSERT(length >= sizeof(struct ieee80211_header)); @@ -162,6 +186,6 @@ void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, const uint8_t* b /* Parsing frame */ if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - ac_ieee80211_mgmt_packet(sessiondata, (const struct ieee80211_header_mgmt*)buffer, length, framecontrol_subtype); + ac_ieee80211_mgmt_packet(sessiondata, radioid, (const struct ieee80211_header_mgmt*)buffer, length, framecontrol_subtype); } } diff --git a/src/ac/ac_session.c b/src/ac/ac_session.c index 9330547..e9ad270 100644 --- a/src/ac/ac_session.c +++ b/src/ac/ac_session.c @@ -63,7 +63,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not /* Check if WLAN id is valid and not used */ if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) { return AC_ERROR_ACTION_SESSION; - } else if (ac_wlans_get_bssid_with_wlanid(session->wlans, notify->radioid, notify->wlanid)) { + } else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) { return AC_ERROR_ACTION_SESSION; } @@ -163,6 +163,12 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses break; } + + case AC_SESSION_ACTION_ROAMING_STATION: { + /* Delete station */ + ac_stations_delete_station(session, (uint8_t*)action->data); + break; + } } return result; @@ -406,7 +412,7 @@ static void ac_session_destroy(struct ac_session_t* session) { } /* Free WLANS */ - ac_wlans_destroy(session->wlans); + ac_wlans_destroy(session); /* */ capwap_event_destroy(&session->changereference); diff --git a/src/ac/ac_session.h b/src/ac/ac_session.h index 5c30ee9..3354a4d 100644 --- a/src/ac/ac_session.h +++ b/src/ac/ac_session.h @@ -25,6 +25,8 @@ struct ac_session_control { #define AC_SESSION_ACTION_NOTIFY_EVENT 3 #define AC_SESSION_ACTION_ADDWLAN 4 +#define AC_SESSION_ACTION_ROAMING_STATION 10 + /* */ struct ac_session_action { long action; @@ -134,7 +136,7 @@ struct ac_session_t { /* 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_send_action(struct ac_session_t* session, long action, long param, const void* data, long length); 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); @@ -146,7 +148,7 @@ void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long act void ac_session_data_release_reference(struct ac_session_data_t* sessiondata); /* IEEE802.11 Packet */ -void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, const uint8_t* buffer, int length); +void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const uint8_t* buffer, int length); /* */ int ac_has_sessionid(struct capwap_sessionid_element* sessionid); diff --git a/src/ac/ac_session_data.c b/src/ac/ac_session_data.c index 57bb72b..ee255fc 100644 --- a/src/ac/ac_session_data.c +++ b/src/ac/ac_session_data.c @@ -305,6 +305,7 @@ static void ac_session_data_run(struct ac_session_data_t* sessiondata) { int length; struct capwap_connection connection; char buffer[CAPWAP_MAX_PACKET_SIZE]; + uint8_t radioid; unsigned short binding; int bodypacketlength; uint8_t bodypacket[AC_BODY_PACKET_MAX_SIZE]; @@ -367,9 +368,10 @@ static void ac_session_data_run(struct ac_session_data_t* sessiondata) { /* Parsing body packet */ if (bodypacketlength > 0) { + radioid = GET_RID_HEADER(sessiondata->rxmngpacket->header); binding = GET_WBID_HEADER(sessiondata->rxmngpacket->header); if ((binding == CAPWAP_WIRELESS_BINDING_IEEE80211) && (bodypacketlength >= sizeof(struct ieee80211_header))) { - ac_ieee80211_packet(sessiondata, bodypacket, bodypacketlength); + ac_ieee80211_packet(sessiondata, radioid, bodypacket, bodypacketlength); } } } diff --git a/src/ac/ac_wlans.c b/src/ac/ac_wlans.c index 0b3fca2..d8bd0bb 100644 --- a/src/ac/ac_wlans.c +++ b/src/ac/ac_wlans.c @@ -3,46 +3,123 @@ #include "ac_wlans.h" /* */ -struct ac_wlans* ac_wlans_init(void) { - struct ac_wlans* wlans; +static void ac_stations_delete_station_from_global_cache(struct ac_session_t* session, uint8_t* address) { + struct ac_session_t* ownersession; + + ASSERT(session != NULL); + ASSERT(address != NULL); /* */ - wlans = (struct ac_wlans*)capwap_alloc(sizeof(struct ac_wlans)); - memset(wlans, 0, sizeof(struct ac_wlans)); + capwap_rwlock_wrlock(&g_ac.stationslock); - return wlans; + /* Can delete global reference only if match session handler */ + ownersession = (struct ac_session_t*)capwap_hash_search(g_ac.stations, address); + if (ownersession == session) { + capwap_hash_delete(g_ac.stations, address); + } + + capwap_rwlock_exit(&g_ac.stationslock); } /* */ -void ac_wlans_destroy(struct ac_wlans* wlans) { - int i; +static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_station* station) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; - ASSERT(wlans != NULL); + ASSERT(session != NULL); + ASSERT(station != NULL); + + /* */ + capwap_logging_info("Destroy station: %s", capwap_printf_macaddress(buffer, station->address, MACADDRESS_EUI48_LENGTH)); + + /* Remove reference from Global Cache Stations List */ + ac_stations_delete_station_from_global_cache(session, station->address); + + /* Remove reference from WLAN */ + if (station->wlan) { + capwap_itemlist_remove(station->wlan->stations, station->wlanitem); + } + + /* */ + capwap_hash_delete(session->wlans->stations, station->address); + + /* Free station reference with itemlist */ + capwap_itemlist_free(station->wlanitem); +} + +/* */ +static unsigned long ac_wlans_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { + uint8_t* macaddress = (uint8_t*)key; + + ASSERT(keysize == MACADDRESS_EUI48_LENGTH); + + return (unsigned long)(macaddress[3] ^ macaddress[4] ^ macaddress[5]); +} + +/* */ +static void ac_stations_reset_station(struct ac_station* station, struct ac_wlan* wlan) { + ASSERT(station != NULL); + ASSERT(wlan != NULL); + + /* Remove reference from current WLAN */ + if (station->wlan) { + capwap_itemlist_remove(station->wlan->stations, station->wlanitem); + } + + /* Set WLAN */ + station->wlan = wlan; + capwap_itemlist_insert_after(wlan->stations, NULL, station->wlanitem); +} + +/* */ +void ac_wlans_init(struct ac_session_t* session) { + ASSERT(session != NULL); + + /* */ + session->wlans = (struct ac_wlans*)capwap_alloc(sizeof(struct ac_wlans)); + memset(session->wlans, 0, sizeof(struct ac_wlans)); + + /* */ + session->wlans->stations = capwap_hash_create(AC_WLANS_STATIONS_HASH_SIZE, AC_WLANS_STATIONS_KEY_SIZE, ac_wlans_item_gethash, NULL, NULL); +} + +/* */ +void ac_wlans_destroy(struct ac_session_t* session) { + int i; + struct capwap_list* items; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); /* */ for (i = 0; i < RADIOID_MAX_COUNT; i++) { - if (wlans->wlans[i]) { - while (wlans->wlans[i]->first) { - struct ac_wlan* wlan = (struct ac_wlan*)wlans->wlans[i]->first->item; + if (session->wlans->wlans[i]) { + items = session->wlans->wlans[i]; - /* Delete WLAN */ - ac_wlans_delete_bssid(wlans, i + 1, wlan->bssid); + /* Delete WLANS */ + while (items->first) { + ac_wlans_delete_bssid(session, i + 1, ((struct ac_wlan*)items->first->item)->bssid); } - - /* TODO */ - capwap_list_free(wlans->wlans[i]); - } + + /* */ + capwap_list_free(items); + } } - capwap_free(wlans); + /* */ + ASSERT(session->wlans->stations->count == 0); + + /* */ + capwap_hash_free(session->wlans->stations); + capwap_free(session->wlans); } /* */ -struct ac_wlan* ac_wlans_create_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t wlanid, uint8_t* bssid) { +struct ac_wlan* ac_wlans_create_bssid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid) { struct ac_wlan* wlan; struct capwap_list_item* wlanitem; - ASSERT(wlans != NULL); + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(IS_VALID_WLANID(wlanid)); ASSERT(bssid != NULL); @@ -54,32 +131,34 @@ struct ac_wlan* ac_wlans_create_bssid(struct ac_wlans* wlans, uint8_t radioid, u /* Init WLAN */ memcpy(wlan->bssid, bssid, MACADDRESS_EUI48_LENGTH); + wlan->radioid = radioid; wlan->wlanid = wlanid; wlan->stations = capwap_list_create(); /* Create WLAN list */ - if (!wlans->wlans[radioid - 1]) { - wlans->wlans[radioid - 1] = capwap_list_create(); + if (!session->wlans->wlans[radioid - 1]) { + session->wlans->wlans[radioid - 1] = capwap_list_create(); } /* Append WLAN to list */ - capwap_itemlist_insert_after(wlans->wlans[radioid - 1], NULL, wlanitem); + capwap_itemlist_insert_after(session->wlans->wlans[radioid - 1], NULL, wlanitem); return wlan; } /* */ -struct ac_wlan* ac_wlans_get_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t* bssid) { +struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { struct capwap_list_item* search; struct ac_wlan* wlan = NULL; - ASSERT(wlans != NULL); + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(bssid != NULL); /* */ - if (wlans->wlans[radioid - 1]) { - search = wlans->wlans[radioid - 1]->first; + if (session->wlans->wlans[radioid - 1]) { + search = session->wlans->wlans[radioid - 1]->first; while (search) { struct ac_wlan* item = (struct ac_wlan*)search->item; @@ -97,17 +176,18 @@ struct ac_wlan* ac_wlans_get_bssid(struct ac_wlans* wlans, uint8_t radioid, uint } /* */ -struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_wlans* wlans, uint8_t radioid, uint8_t wlanid) { +struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid) { struct capwap_list_item* search; struct ac_wlan* wlan = NULL; - ASSERT(wlans != NULL); + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(IS_VALID_WLANID(wlanid)); /* */ - if (wlans->wlans[radioid - 1]) { - search = wlans->wlans[radioid - 1]->first; + if (session->wlans->wlans[radioid - 1]) { + search = session->wlans->wlans[radioid - 1]->first; while (search) { struct ac_wlan* item = (struct ac_wlan*)search->item; @@ -125,7 +205,7 @@ struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_wlans* wlans, uint8_t r } /* */ -static void ac_wlans_destroy_bssid(struct ac_wlan* wlan) { +static void ac_wlans_destroy_bssid(struct ac_session_t* session, struct ac_wlan* wlan) { /* Free capability */ if (wlan->key) { capwap_free(wlan->key); @@ -136,26 +216,32 @@ static void ac_wlans_destroy_bssid(struct ac_wlan* wlan) { } /* Remove stations */ + while (wlan->stations->first) { + ac_stations_destroy_station(session, (struct ac_station*)wlan->stations->first->item); + } + + /* */ capwap_list_free(wlan->stations); } /* */ -void ac_wlans_delete_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t* bssid) { +void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { struct capwap_list_item* search; - ASSERT(wlans != NULL); + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(bssid != NULL); /* */ - if (wlans->wlans[radioid - 1]) { - search = wlans->wlans[radioid - 1]->first; + if (session->wlans->wlans[radioid - 1]) { + search = session->wlans->wlans[radioid - 1]->first; while (search) { struct ac_wlan* item = (struct ac_wlan*)search->item; if (!memcmp(bssid, item->bssid, MACADDRESS_EUI48_LENGTH)) { - ac_wlans_destroy_bssid(item); - capwap_itemlist_free(capwap_itemlist_remove(wlans->wlans[radioid - 1], search)); + ac_wlans_destroy_bssid(session, item); + capwap_itemlist_free(capwap_itemlist_remove(session->wlans->wlans[radioid - 1], search)); break; } @@ -189,3 +275,97 @@ void ac_wlans_set_bssid_capability(struct ac_wlan* wlan, struct capwap_80211_add wlan->suppressssid = addwlan->suppressssid; wlan->ssid = (uint8_t*)capwap_duplicate_string((const char*)addwlan->ssid); } + +/* */ +struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { + struct ac_station* station; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(bssid != NULL); + ASSERT(address != NULL); + + /* Get station */ + station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); + if (station && (radioid == station->wlan->radioid) && !memcmp(bssid, station->wlan->bssid, MACADDRESS_EUI48_LENGTH)) { + return station; + } + + return NULL; +} + +/* */ +struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { + char buffer1[CAPWAP_MACADDRESS_EUI48_BUFFER]; + char buffer2[CAPWAP_MACADDRESS_EUI48_BUFFER]; + struct ac_wlan* wlan; + struct ac_session_t* ownersession; + struct ac_station* station; + struct capwap_list_item* stationitem; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(bssid != NULL); + ASSERT(address != NULL); + + /* */ + capwap_printf_macaddress(buffer1, bssid, MACADDRESS_EUI48_LENGTH); + capwap_printf_macaddress(buffer2, address, MACADDRESS_EUI48_LENGTH); + capwap_logging_info("Create station to radioid: %d, bssid: %s, station address: %s", (int)radioid, buffer1, buffer2); + + /* Get session that owns the station */ + capwap_rwlock_rdlock(&g_ac.stationslock); + ownersession = (struct ac_session_t*)capwap_hash_search(g_ac.stations, address); + capwap_rwlock_exit(&g_ac.stationslock); + + /* If request change owner of station */ + if (ownersession != session) { + /* Release station from old owner */ + if (ownersession) { + ac_session_send_action(ownersession, AC_SESSION_ACTION_ROAMING_STATION, 0, (void*)address, MACADDRESS_EUI48_LENGTH); + } + + /* Set station into Global Cache Stations List */ + capwap_rwlock_wrlock(&g_ac.stationslock); + capwap_hash_add(g_ac.stations, address, session); + capwap_rwlock_exit(&g_ac.stationslock); + } + + /* */ + wlan = ac_wlans_get_bssid(session, radioid, bssid); + station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); + if (!station) { + stationitem = capwap_itemlist_create(sizeof(struct ac_station)); + station = (struct ac_station*)stationitem->item; + memset(station, 0, sizeof(struct ac_station)); + + /* */ + memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); + station->wlanitem = stationitem; + + /* */ + capwap_hash_add(session->wlans->stations, address, station); + } + + /* Set station to WLAN */ + ac_stations_reset_station(station, wlan); + + return station; +} + +/* */ +void ac_stations_delete_station(struct ac_session_t* session, const uint8_t* address) { + struct ac_station* station; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(address != NULL); + + /* Delete station */ + station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); + if (station) { + ac_stations_destroy_station(session, station); + } +} diff --git a/src/ac/ac_wlans.h b/src/ac/ac_wlans.h index 42e46ab..b8d8523 100644 --- a/src/ac/ac_wlans.h +++ b/src/ac/ac_wlans.h @@ -1,15 +1,25 @@ #ifndef __AC_WLANS_HEADER__ #define __AC_WLANS_HEADER__ +#include "ieee80211.h" + +/* */ +#define AC_WLANS_STATIONS_HASH_SIZE 256 +#define AC_WLANS_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH + /* AC WLAN */ struct ac_wlan { uint8_t bssid[MACADDRESS_EUI48_LENGTH]; + uint8_t radioid; uint8_t wlanid; /* CAPWAP Session */ struct ac_session_t* session; struct ac_session_data_t* sessiondata; + /* Stations reference */ + struct capwap_list* stations; + /* Capability */ uint16_t capability; uint8_t keyindex; @@ -23,9 +33,6 @@ struct ac_wlan { uint8_t tunnelmode; uint8_t suppressssid; uint8_t* ssid; - - /* Local cache stations */ - struct capwap_list* stations; }; /* AC Station */ @@ -33,26 +40,34 @@ struct ac_station { uint8_t address[MACADDRESS_EUI48_LENGTH]; /* Reference of WLAN */ - struct ac_wlan_device* wlan; - struct capwap_list_item* itemlist; + struct ac_wlan* wlan; + struct capwap_list_item* wlanitem; }; /* */ struct ac_wlans { struct capwap_list* wlans[RADIOID_MAX_COUNT]; + + /* Stations */ + struct capwap_hash* stations; }; -/* */ -struct ac_wlans* ac_wlans_init(void); -void ac_wlans_destroy(struct ac_wlans* wlans); +/* Management WLANS */ +void ac_wlans_init(struct ac_session_t* session); +void ac_wlans_destroy(struct ac_session_t* session); /* */ -struct ac_wlan* ac_wlans_create_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t wlanid, uint8_t* bssid); -struct ac_wlan* ac_wlans_get_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t* bssid); -struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_wlans* wlans, uint8_t radioid, uint8_t wlanid); -void ac_wlans_delete_bssid(struct ac_wlans* wlans, uint8_t radioid, uint8_t* bssid); +struct ac_wlan* ac_wlans_create_bssid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid); +struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); +struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid); +void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); /* */ void ac_wlans_set_bssid_capability(struct ac_wlan* wlan, struct capwap_80211_addwlan_element* addwlan); +/* Management Stations */ +struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); +struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); +void ac_stations_delete_station(struct ac_session_t* session, const uint8_t* address); + #endif /* __AC_WLANS_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index c1a8773..405dea3 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -15,12 +15,12 @@ #include "wifi_nl80211.h" /* */ -static char g_bufferIEEE80211[4096]; +static char g_bufferIEEE80211[IEEE80211_MTU]; /* */ static void nl80211_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); static void nl80211_wlan_stopap(wifi_wlan_handle handle); -static void nl80211_wlan_deauthentication_station(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode); +static void nl80211_wlan_deauthentication_station(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode, int reusestation); /* */ static const int g_stypes[] = { @@ -663,8 +663,13 @@ static void nl80211_station_clean(struct nl80211_station* station) { /* */ static void nl80211_station_delete(struct nl80211_station* station) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; + ASSERT(station != NULL); + /* */ + capwap_logging_info("Delete station: %s", capwap_printf_macaddress(buffer, station->address, MACADDRESS_EUI48_LENGTH)); + /* */ nl80211_station_clean(station); @@ -693,10 +698,14 @@ static struct nl80211_station* nl80211_station_get(struct nl80211_global_handle* static struct nl80211_station* nl80211_station_create(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { struct nl80211_station* station; struct nl80211_global_handle* globalhandle; + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; ASSERT(wlanhandle != NULL); ASSERT(macaddress != NULL); + /* */ + capwap_printf_macaddress(buffer, macaddress, MACADDRESS_EUI48_LENGTH); + /* */ globalhandle = wlanhandle->devicehandle->globalhandle; @@ -704,19 +713,25 @@ static struct nl80211_station* nl80211_station_create(struct nl80211_wlan_handle station = nl80211_station_get(globalhandle, NULL, macaddress); if (station) { if (station->wlanhandle && (station->wlanhandle != wlanhandle)) { - nl80211_wlan_deauthentication_station(station->wlanhandle, macaddress, IEEE80211_REASON_PREV_AUTH_NOT_VALID); /* Disconnect from another WLAN */ + capwap_logging_info("Roaming station: %s", buffer); + nl80211_wlan_deauthentication_station(station->wlanhandle, macaddress, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 1); /* Disconnect from another WLAN */ } else { + capwap_logging_info("Reuse station: %s", buffer); nl80211_station_clean(station); } } /* Checks if it has reached the maximum number of stations */ if (wlanhandle->stationscount >= wlanhandle->maxstationscount) { + capwap_logging_warning("Unable create station: reached the maximum number of stations"); return NULL; } /* Create new station */ if (!station) { + capwap_logging_info("Create new station: %s", buffer); + + /* */ station = (struct nl80211_station*)capwap_alloc(sizeof(struct nl80211_station)); memset(station, 0, sizeof(struct nl80211_station)); @@ -738,7 +753,7 @@ static struct nl80211_station* nl80211_station_create(struct nl80211_wlan_handle /* */ static void nl80211_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { - char stationaddress[18]; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; struct nl80211_station* station = (struct nl80211_station*)context; ASSERT(station != NULL); @@ -749,8 +764,6 @@ static void nl80211_station_timeout(struct capwap_timeout* timeout, unsigned lon if (station->idtimeout == index) { switch (station->timeoutaction) { case NL80211_STATION_TIMEOUT_ACTION_DELETE: { - capwap_logging_warning("The %s station has destroyed", stationaddress); - /* Free station into hash callback function */ nl80211_station_clean(station); capwap_hash_delete(station->globalhandle->stations, station->address); @@ -759,8 +772,7 @@ static void nl80211_station_timeout(struct capwap_timeout* timeout, unsigned lon case NL80211_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { capwap_logging_warning("The %s station has not completed the association in time", stationaddress); - nl80211_wlan_deauthentication_station((struct nl80211_wlan_handle*)param, station->address, IEEE80211_REASON_PREV_AUTH_NOT_VALID); - nl80211_station_delete(station); + nl80211_wlan_deauthentication_station((struct nl80211_wlan_handle*)param, station->address, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); break; } } @@ -772,7 +784,7 @@ static void nl80211_wlan_send_deauthentication(struct nl80211_wlan_handle* wlanh int responselength; struct ieee80211_deauthentication_params ieee80211_params; struct wlan_send_frame_params wlan_params; - char stationaddress[18]; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; /* */ capwap_printf_macaddress(stationaddress, station, MACADDRESS_EUI48_LENGTH); @@ -793,6 +805,9 @@ static void nl80211_wlan_send_deauthentication(struct nl80211_wlan_handle* wlanh if (!nl80211_wlan_send_frame((wifi_wlan_handle)wlanhandle, &wlan_params)) { capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); wlanhandle->last_cookie = wlan_params.cookie; + + /* Forwards the station deauthentication also to AC */ + wlanhandle->send_mgmtframe(wlanhandle->send_mgmtframe_to_ac_cbparam, (struct ieee80211_header_mgmt*)g_bufferIEEE80211, responselength); } else { capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); } @@ -880,7 +895,7 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla struct ieee80211_authentication_params ieee80211_params; struct wlan_send_frame_params wlan_params; struct nl80211_station* station; - char stationaddress[18]; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; /* Information Elements packet length */ ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication)); @@ -1101,7 +1116,7 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle struct wlan_send_frame_params wlan_params; struct nl80211_station* station; uint16_t resultstatuscode = IEEE80211_STATUS_SUCCESS; - char stationaddress[18]; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; /* Information Elements packet length */ ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); @@ -1118,19 +1133,14 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle if (!station || !(station->flags & NL80211_STATION_FLAGS_AUTHENTICATED)) { /* Invalid station, send deauthentication message */ capwap_logging_info("Receive IEEE802.11 Association Request from %s unknown station", stationaddress); - nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); - if (station) { - nl80211_station_delete(station); - } - + nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA, 0); return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", stationaddress); - nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID); - nl80211_station_delete(station); + nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); return; } @@ -1168,13 +1178,11 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle wlanhandle->send_mgmtframe(wlanhandle->send_mgmtframe_to_ac_cbparam, mgmt, mgmtlength); } else { capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", stationaddress); - nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID); - nl80211_station_delete(station); + nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else { capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", stationaddress); - nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID); - nl80211_station_delete(station); + nl80211_wlan_deauthentication_station(wlanhandle, mgmt->sa, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else if ((wlanhandle->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) && (resultstatuscode == IEEE80211_STATUS_SUCCESS)) { wlanhandle->send_mgmtframe(wlanhandle->send_mgmtframe_to_ac_cbparam, mgmt, mgmtlength); @@ -1488,10 +1496,14 @@ static unsigned long nl80211_hash_station_gethash(const void* key, unsigned long /* */ static void nl80211_hash_station_free(const void* key, unsigned long keysize, void* data) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; struct nl80211_station* station = (struct nl80211_station*)data; ASSERT(data != NULL); + /* */ + capwap_logging_info("Destroy station: %s", capwap_printf_macaddress(buffer, (uint8_t*)key, MACADDRESS_EUI48_LENGTH)); + capwap_free(station); } @@ -1545,11 +1557,7 @@ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { wlanhandle = nl80211_global_search_wlan(globalhandle, ifindex); if (wlanhandle) { return nl80211_execute_bss_event(wlanhandle, gnlh, tb_msg); - } else { - capwap_logging_debug("*** Receive nl80211_global_valid_handler without found interface: %d", (int)ifindex); } - } else { - capwap_logging_debug("*** Receive nl80211_global_valid_handler without interface index"); } return NL_SKIP; @@ -2650,7 +2658,7 @@ static int nl80211_wlan_getmacaddress(wifi_wlan_handle handle, uint8_t* address) } /* */ -static void nl80211_wlan_deauthentication_station(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode) { +static void nl80211_wlan_deauthentication_station(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode, int reusestation) { struct nl80211_station* station; ASSERT(wlanhandle != NULL); @@ -2665,7 +2673,11 @@ static void nl80211_wlan_deauthentication_station(struct nl80211_wlan_handle* wl /* Clean station */ station = nl80211_station_get(wlanhandle->devicehandle->globalhandle, wlanhandle, stationaddress); if (station) { - nl80211_station_clean(station); + if (reusestation) { + nl80211_station_clean(station); + } else { + nl80211_station_delete(station); + } } } diff --git a/src/common/capwap_element.c b/src/common/capwap_element.c index bb851a3..cc28265 100644 --- a/src/common/capwap_element.c +++ b/src/common/capwap_element.c @@ -700,7 +700,11 @@ int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct ca return 0; } } else { - return 0; + /* Validate Radio ID */ + uint8_t radioid = GET_RID_HEADER(packet->rxmngpacket->header); + if (IS_VALID_RADIOID(radioid)) { + return 0; + } } } diff --git a/src/common/capwap_hash.c b/src/common/capwap_hash.c index 635871b..270f638 100644 --- a/src/common/capwap_hash.c +++ b/src/common/capwap_hash.c @@ -248,20 +248,21 @@ static int capwap_hash_item_memcmp(const void* key1, const void* key2, unsigned } /* */ -struct capwap_hash* capwap_hash_create(unsigned long count, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free) { +struct capwap_hash* capwap_hash_create(unsigned long hashsize, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free) { unsigned long size; struct capwap_hash* hash; - ASSERT(count > 0); + ASSERT(hashsize > 0); ASSERT(keysize > 0); ASSERT(item_hash != NULL); - size = sizeof(struct capwap_hash_item*) * count; + size = sizeof(struct capwap_hash_item*) * hashsize; /* */ hash = (struct capwap_hash*)capwap_alloc(sizeof(struct capwap_hash)); - hash->count = count; + hash->hashsize = hashsize; hash->keysize = keysize; + hash->count = 0; hash->items = (struct capwap_hash_item**)capwap_alloc(size); memset(hash->items, 0, size); hash->item_hash = item_hash; @@ -293,12 +294,14 @@ void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data) { ASSERT(hash != NULL); ASSERT(key != NULL); - hashvalue = hash->item_hash(key, hash->keysize, hash->count); - ASSERT(hashvalue < hash->count); + /* */ + hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); + ASSERT(hashvalue < hash->hashsize); /* Search position where insert item */ search = hash->items[hashvalue]; if (!search) { + hash->count++; hash->items[hashvalue] = capwap_hash_create_item(hash, key, data); } else { while (search) { @@ -315,6 +318,7 @@ void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data) { if (search->left) { search = search->left; } else { + hash->count++; item = capwap_hash_create_item(hash, key, data); capwap_hash_set_left_item(search, item); break; @@ -323,6 +327,7 @@ void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data) { if (search->right) { search = search->right; } else { + hash->count++; item = capwap_hash_create_item(hash, key, data); capwap_hash_set_right_item(search, item); break; @@ -351,7 +356,7 @@ void capwap_hash_delete(struct capwap_hash* hash, const void* key) { ASSERT(key != NULL); /* */ - hashvalue = hash->item_hash(key, hash->keysize, hash->count); + hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); if (!hash->items[hashvalue]) { return; } @@ -362,6 +367,9 @@ void capwap_hash_delete(struct capwap_hash* hash, const void* key) { return; } + /* */ + ASSERT(hash->count > 0); + /* Rebalancing tree */ parent = search->parent; if (!search->left && !search->right) { @@ -453,6 +461,7 @@ void capwap_hash_delete(struct capwap_hash* hash, const void* key) { } /* Free node */ + hash->count--; capwap_hash_free_item(hash, search); } @@ -462,13 +471,15 @@ void capwap_hash_deleteall(struct capwap_hash* hash) { ASSERT(hash != NULL); - for (i = 0; i < hash->count; i++) { + for (i = 0; i < hash->hashsize; i++) { if (hash->items[i]) { capwap_hash_free_items(hash, hash->items[i]); hash->items[i] = NULL; } } + /* */ + hash->count = 0; } /* */ @@ -481,7 +492,7 @@ int capwap_hash_hasitem(struct capwap_hash* hash, const void* key) { ASSERT(key != NULL); /* Search item */ - hashvalue = hash->item_hash(key, hash->keysize, hash->count); + hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); items = hash->items[hashvalue]; if (!items) { return 0; @@ -502,7 +513,7 @@ void* capwap_hash_search(struct capwap_hash* hash, const void* key) { ASSERT(key != NULL); /* Search item */ - hashvalue = hash->item_hash(key, hash->keysize, hash->count); + hashvalue = hash->item_hash(key, hash->keysize, hash->hashsize); items = hash->items[hashvalue]; if (!items) { return NULL; @@ -524,7 +535,7 @@ void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item ASSERT(hash != NULL); ASSERT(item_foreach != NULL); - for (i = 0; i < hash->count; i++) { + for (i = 0; i < hash->hashsize; i++) { if (hash->items[i]) { capwap_hash_foreach_items(hash, hash->items[i], item_foreach, param); } diff --git a/src/common/capwap_hash.h b/src/common/capwap_hash.h index f4b1007..7e556a6 100644 --- a/src/common/capwap_hash.h +++ b/src/common/capwap_hash.h @@ -20,16 +20,19 @@ struct capwap_hash_item { struct capwap_hash { struct capwap_hash_item** items; - unsigned long count; + unsigned long hashsize; unsigned long keysize; + /* */ + unsigned long count; + /* Callback functions */ capwap_hash_item_gethash item_hash; capwap_hash_item_cmp item_cmp; capwap_hash_item_free item_free; }; -struct capwap_hash* capwap_hash_create(unsigned long count, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free); +struct capwap_hash* capwap_hash_create(unsigned long hashsize, unsigned long keysize, capwap_hash_item_gethash item_hash, capwap_hash_item_cmp item_cmp, capwap_hash_item_free item_free); void capwap_hash_free(struct capwap_hash* hash); void capwap_hash_add(struct capwap_hash* hash, const void* key, void* data); diff --git a/src/common/capwap_network.h b/src/common/capwap_network.h index 31c3fe2..9c08991 100644 --- a/src/common/capwap_network.h +++ b/src/common/capwap_network.h @@ -8,6 +8,10 @@ #define CAPWAP_CONTROL_PORT 5246 #define CAPWAP_MAX_PACKET_SIZE 65535 +/* */ +#define CAPWAP_MACADDRESS_EUI48_BUFFER 18 +#define CAPWAP_MACADDRESS_EUI64_BUFFER 24 + /* Helper */ #define CAPWAP_GET_NETWORK_PORT(address) ntohs((((address)->ss_family == AF_INET) ? ((struct sockaddr_in*)(address))->sin_port : ((struct sockaddr_in6*)(address))->sin6_port)) #define CAPWAP_SET_NETWORK_PORT(address, port) if ((address)->ss_family == AF_INET) { \ diff --git a/src/common/capwap_rfc.h b/src/common/capwap_rfc.h index dc3e556..ba27ce8 100644 --- a/src/common/capwap_rfc.h +++ b/src/common/capwap_rfc.h @@ -155,10 +155,10 @@ struct capwap_data_message { #define GET_HLEN_HEADER(x) ((x)->hlen) #define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) #ifdef CAPWAP_BIG_ENDIAN - #define GET_RID_HEADER(x) ((x)->rid) + #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) #else - #define GET_RID_HEADER(x) ((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo)) + #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) #endif #define GET_WBID_HEADER(x) ((x)->wbid) diff --git a/src/common/capwap_timeout.c b/src/common/capwap_timeout.c index 4062167..f1ab3ad 100644 --- a/src/common/capwap_timeout.c +++ b/src/common/capwap_timeout.c @@ -3,6 +3,9 @@ /* */ #define CAPWAP_TIMEOUT_HASH_COUNT 128 +/* */ +/* #define CAPWAP_TIMEOUT_LOGGING_DEBUG 1 */ + /* */ static unsigned long capwap_timeout_hash_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { return (*(unsigned long*)key % hashsize); @@ -121,7 +124,10 @@ unsigned long capwap_timeout_createtimer(struct capwap_timeout* timeout) { /* Create new timeout index */ index = capwap_timeout_set_bitfield(timeout); + +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Create new timer: %lu", index); +#endif return index; } @@ -131,7 +137,9 @@ void capwap_timeout_deletetimer(struct capwap_timeout* timeout, unsigned long in ASSERT(timeout != NULL); if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Delete timer: %lu", index); +#endif /* Unset timeout timer */ capwap_timeout_unset(timeout, index); @@ -169,7 +177,9 @@ unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long i item->context = context; item->param = param; +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Update timeout: %lu %ld", item->index, item->durate); +#endif /* Add itemlist into order list */ capwap_timeout_additem(timeout->itemstimeout, itemlist); @@ -189,7 +199,9 @@ unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long i item->context = context; item->param = param; +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Set timeout: %lu %ld", item->index, item->durate); +#endif /* Add itemlist into hash for rapid searching */ capwap_hash_add(timeout->itemsreference, (const void*)&item->index, (void*)itemlist); @@ -209,7 +221,11 @@ void capwap_timeout_unset(struct capwap_timeout* timeout, unsigned long index) { if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { itemlist = (struct capwap_list_item*)capwap_hash_search(timeout->itemsreference, &index); if (itemlist) { +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Unset timeout: %lu", index); +#endif + + /* */ capwap_hash_delete(timeout->itemsreference, &index); capwap_itemlist_free(capwap_itemlist_remove(timeout->itemstimeout, itemlist)); } @@ -281,7 +297,9 @@ unsigned long capwap_timeout_hasexpired(struct capwap_timeout* timeout) { itemlist = capwap_itemlist_remove_head(timeout->itemstimeout); item = (struct capwap_timeout_item*)itemlist->item; +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG capwap_logging_debug("Expired timeout: %lu", item->index); +#endif /* Cache callback before release timeout timer */ index = item->index;