#include "wtp.h" #include "capwap_list.h" #include "capwap_element.h" #include "wifi_drivers.h" #include "wtp_radio.h" #include "wtp_kmod.h" /* Declare enable wifi driver */ #ifdef ENABLE_WIFI_DRIVERS_NL80211 extern struct wifi_driver_ops wifi_driver_nl80211_ops; #endif static struct wifi_driver_instance wifi_driver[] = { #ifdef ENABLE_WIFI_DRIVERS_NL80211 { &wifi_driver_nl80211_ops, NULL }, #endif { NULL, NULL } }; /* */ #define WIFI_STATIONS_HASH_SIZE 256 #define WIFI_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH /* Wifi Manager */ static struct wifi_global g_wifiglobal; static uint8_t g_bufferIEEE80211[IEEE80211_MTU]; /* */ static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation); /* */ static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int ratescount, struct device_setrates_params* device_params) { int i, j, w; int radiotype; uint32_t mode = 0; const struct wifi_capability* capability; ASSERT(device != NULL); ASSERT(rates != NULL); ASSERT(ratescount > 0); ASSERT(device_params != NULL); /* */ memset(device_params, 0, sizeof(struct device_setrates_params)); /* Retrieve capability */ capability = wifi_device_getcapability(device); if (!capability) { return; } /* Get radio type for basic rate */ radiotype = wifi_frequency_to_radiotype(device->currentfrequency.frequency); if (radiotype < 0) { return; } /* Check type of rate mode */ for (i = 0; i < ratescount; i++) { if (device->currentfrequency.band == WIFI_BAND_2GHZ) { if (IS_IEEE80211_RATE_B(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211B; } else if (IS_IEEE80211_RATE_G(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211G; } else if (IS_IEEE80211_RATE_N(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211N; } } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { if (IS_IEEE80211_RATE_A(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211A; } else if (IS_IEEE80211_RATE_N(rates[i])) { mode |= CAPWAP_RADIO_TYPE_80211N; } } } /* Add implicit 802.11b rate with only 802.11g rate */ if ((device->currentfrequency.band == WIFI_BAND_2GHZ) && !(mode & CAPWAP_RADIO_TYPE_80211B) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211B)) { device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_1M; device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_2M; device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_5_5M; device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_11M; } /* Filter band */ for (i = 0; i < capability->bands->count; i++) { struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); if (bandcap->band == device->currentfrequency.band) { for (j = 0; j < bandcap->rate->count; j++) { struct wifi_rate_capability* ratecapability = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); /* Validate rate */ for (w = 0; w < ratescount; w++) { if (rates[w] == ratecapability->bitrate) { device_params->supportedrates[device_params->supportedratescount++] = ratecapability->bitrate; break; } } } break; } } /* Apply basic rate */ for (i = 0; i < device_params->supportedratescount; i++) { if (radiotype == CAPWAP_RADIO_TYPE_80211A) { if (IS_IEEE80211_BASICRATE_A(device_params->supportedrates[i])) { device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; device_params->supportedrates[i] |= IEEE80211_BASICRATE; } } else if (radiotype == CAPWAP_RADIO_TYPE_80211B) { if (IS_IEEE80211_BASICRATE_B(device_params->supportedrates[i])) { device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; device_params->supportedrates[i] |= IEEE80211_BASICRATE; } } else if (radiotype == CAPWAP_RADIO_TYPE_80211G) { if (IS_IEEE80211_BASICRATE_G(device_params->supportedrates[i])) { device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; device_params->supportedrates[i] |= IEEE80211_BASICRATE; } } } /* Add implicit 802.11n rate with only 802.11a/g rate */ if (!(mode & CAPWAP_RADIO_TYPE_80211N) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211N)) { device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_80211N; } } /* */ static unsigned long wifi_hash_station_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] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]); } /* */ static void wifi_hash_station_free(const void* key, unsigned long keysize, void* data) { struct wifi_station* station = (struct wifi_station*)data; ASSERT(data != NULL); /* */ capwap_logging_info("Destroy station: %s", station->addrtext); capwap_free(station); } /* */ static struct wifi_station* wifi_station_get(struct wifi_wlan* wlan, const uint8_t* address) { struct wifi_station* station; ASSERT(address != NULL); /* Get station */ station = (struct wifi_station*)capwap_hash_search(g_wifiglobal.stations, address); if (station && wlan && (station->wlan != wlan)) { return NULL; } return station; } /* */ static void wifi_station_clean(struct wifi_station* station) { int updatebeacons = 0; ASSERT(station != NULL); if (station->wlan) { struct wifi_wlan* wlan = station->wlan; /* Delete station into wireless driver */ if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { wlan->device->instance->ops->station_deauthorize(wlan, station->address); } if (station->aid && (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { ieee80211_aid_free(wlan->aidbitfield, station->aid); station->aid = 0; } if (station->flags & WIFI_STATION_FLAGS_NON_ERP) { wlan->device->stationsnonerpcount--; if (!wlan->device->stationsnonerpcount) { updatebeacons = 1; } } if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME) { wlan->device->stationsnoshortslottimecount--; if (!wlan->device->stationsnoshortslottimecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { updatebeacons = 1; } } if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE) { wlan->device->stationsnoshortpreamblecount--; if (!wlan->device->stationsnoshortpreamblecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { updatebeacons = 1; } } /* Update beacons */ if (updatebeacons) { wlan->device->instance->ops->device_updatebeacons(wlan->device); } /* Disconnet from WLAN */ wlan->stationscount--; station->wlan = NULL; } /* Remove timers */ if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; } /* */ station->flags = 0; station->supportedratescount = 0; } /* */ static void wifi_station_delete(struct wifi_station* station) { ASSERT(station != NULL); /* */ capwap_logging_info("Delete station: %s", station->addrtext); /* */ wifi_station_clean(station); /* Delay delete station */ station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DELETE; station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED, wifi_station_timeout, station, NULL); } /* */ static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const uint8_t* address) { struct wifi_station* station; char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; ASSERT(wlan != NULL); ASSERT(address != NULL); /* */ capwap_printf_macaddress(buffer, address, MACADDRESS_EUI48_LENGTH); /* */ station = wifi_station_get(NULL, address); if (station) { if (station->wlan && (station->wlan != wlan)) { capwap_logging_info("Roaming station: %s", buffer); wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 1); } else { capwap_logging_info("Reuse station: %s", buffer); wifi_station_clean(station); } } /* Checks if it has reached the maximum number of stations */ if (wlan->stationscount >= wlan->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 wifi_station*)capwap_alloc(sizeof(struct wifi_station)); memset(station, 0, sizeof(struct wifi_station)); /* Initialize station */ memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; /* Add to pool */ capwap_hash_add(g_wifiglobal.stations, address, station); } /* Set station to WLAN */ station->wlan = wlan; wlan->stationscount++; return station; } /* */ static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode) { int responselength; struct ieee80211_deauthentication_params ieee80211_params; char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; /* */ capwap_printf_macaddress(stationaddress, station, MACADDRESS_EUI48_LENGTH); /* Create deauthentication packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); memcpy(ieee80211_params.station, station, ETH_ALEN); ieee80211_params.reasoncode = reasoncode; responselength = ieee80211_create_deauthentication(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); if (responselength > 0) { if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); /* Forwards the station deauthentication also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); } else { capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); } } else { capwap_logging_warning("Unable to create IEEE802.11 Deauthentication to %s station", stationaddress); } } /* */ static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation) { ASSERT(wlan != NULL); ASSERT(station != NULL); /* Send deauthentication message */ if (station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) { wifi_wlan_send_mgmt_deauthentication(wlan, station->address, reasoncode); } /* Clean station */ if (reusestation) { wifi_station_clean(station); } else { wifi_station_delete(station); } } /* */ static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { struct wifi_station* station = (struct wifi_station*)context; ASSERT(station != NULL); if (station->idtimeout == index) { switch (station->timeoutaction) { case WIFI_STATION_TIMEOUT_ACTION_DELETE: { /* Free station into hash callback function */ wifi_station_clean(station); capwap_hash_delete(g_wifiglobal.stations, station->address); break; } case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); wifi_wlan_deauthentication_station((struct wifi_wlan*)param, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); break; } } } } /* */ static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int ielength; int ssidcheck; int nowaitack; int responselength; struct ieee80211_ie_items ieitems; struct ieee80211_probe_response_params ieee80211_params; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->proberequest)); if (ielength < 0) { return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->proberequest.ie[0], ielength)) { return; } /* Validate Probe Request Packet */ if (!ieitems.ssid || !ieitems.supported_rates) { return; } /* Verify the SSID */ ssidcheck = ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, ieitems.ssid_list); if (ssidcheck == IEEE80211_WRONG_SSID) { return; } /* Create probe response */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_probe_response_params)); memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); ieee80211_params.beaconperiod = wlan->device->beaconperiod; ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); ieee80211_params.ssid = wlan->ssid; memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); ieee80211_params.supportedratescount = wlan->device->supportedratescount; ieee80211_params.mode = wlan->device->currentfrequency.mode; ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); ieee80211_params.channel = wlan->device->currentfrequency.channel; responselength = ieee80211_create_probe_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); if (responselength < 0) { return; } /* Send probe response */ nowaitack = ((ssidcheck == IEEE80211_WILDCARD_SSID) && ieee80211_is_broadcast_addr(frame->da) ? 1 : 0); if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { /* If enable Split Mac send the probe request message to AC */ if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); } } else { capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); } } /* */ static void wifi_wlan_management_legacy_station(struct wifi_wlan* wlan, struct wifi_station* station) { int updatebeacons = 0; /* Check NON ERP */ if (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) { int i; int stationnonerp = 1; for (i = 0; i < station->supportedratescount; i++) { if (IS_IEEE80211_RATE_G(station->supportedrates[i])) { stationnonerp = 0; break; } } if (stationnonerp) { station->flags |= WIFI_STATION_FLAGS_NON_ERP; wlan->device->stationsnonerpcount++; if (wlan->device->stationsnonerpcount == 1) { updatebeacons = 1; } } } /* Check short slot capability */ if (!(station->capability & IEEE80211_CAPABILITY_SHORTSLOTTIME)) { station->flags |= WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME; wlan->device->stationsnoshortslottimecount++; if ((wlan->device->stationsnoshortslottimecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { updatebeacons = 1; } } /* Check short preamble capability */ if (!(station->capability & IEEE80211_CAPABILITY_SHORTPREAMBLE)) { station->flags |= WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE; wlan->device->stationsnoshortpreamblecount++; if ((wlan->device->stationsnoshortpreamblecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { updatebeacons = 1; } } /* Update beacon */ if (updatebeacons) { wlan->device->instance->ops->device_updatebeacons(wlan->device); } } /* */ static int wifi_wlan_get_station_rates(struct wifi_station* station, struct ieee80211_ie_items* ieitems) { if (!ieitems->supported_rates) { return -1; } else if ((ieitems->supported_rates->len + (ieitems->extended_supported_rates ? ieitems->extended_supported_rates->len : 0)) > sizeof(station->supportedrates)) { return -1; } /* */ station->supportedratescount = ieitems->supported_rates->len; memcpy(station->supportedrates, ieitems->supported_rates->rates, ieitems->supported_rates->len); if (ieitems->extended_supported_rates) { station->supportedratescount += ieitems->extended_supported_rates->len; memcpy(&station->supportedrates[ieitems->supported_rates->len], ieitems->extended_supported_rates->rates, ieitems->extended_supported_rates->len); } return 0; } /* */ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int acl; int ielength; struct ieee80211_ie_items ieitems; int responselength; struct ieee80211_authentication_params ieee80211_params; struct wifi_station* station; char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; uint16_t responsestatuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); if (ielength < 0) { capwap_logging_info("Receive invalid IEEE802.11 Authentication Request"); return; } /* Ignore authentication packet from same AP */ if (!memcmp(frame->sa, wlan->address, MACADDRESS_EUI48_LENGTH)) { capwap_logging_info("Ignore IEEE802.11 Authentication Request from same AP"); return; } /* */ capwap_printf_macaddress(stationaddress, frame->sa, MACADDRESS_EUI48_LENGTH); /* Get ACL Station */ acl = wtp_radio_acl_station(frame->sa); if (acl == WTP_RADIO_ACL_STATION_DENY) { capwap_logging_info("Denied IEEE802.11 Authentication Request from %s station", stationaddress); return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->authetication.ie[0], ielength)) { capwap_logging_info("Invalid IEEE802.11 Authentication Request from %s station", stationaddress); return; } /* */ capwap_logging_info("Receive IEEE802.11 Authentication Request from %s station", stationaddress); /* Create station reference */ station = wifi_station_create(wlan, frame->sa); if (station) { /* A station is removed if the association does not complete within a given period of time */ station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE, wifi_station_timeout, station, wlan); responsestatuscode = IEEE80211_STATUS_SUCCESS; } else { responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; } /* */ if ((responsestatuscode != IEEE80211_STATUS_SUCCESS) || (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); /* Check authentication algorithm */ if (responsestatuscode == IEEE80211_STATUS_SUCCESS) { responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { if (transactionseqnumber == 1) { responsestatuscode = IEEE80211_STATUS_SUCCESS; station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; } else { responsestatuscode = IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION; } } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { /* TODO */ } } /* Create authentication packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); ieee80211_params.algorithm = algorithm; ieee80211_params.transactionseqnumber = transactionseqnumber + 1; ieee80211_params.statuscode = responsestatuscode; responselength = ieee80211_create_authentication_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); if (responselength > 0) { /* Send authentication response */ if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode); /* Notify authentication request message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); /* Forwards the authentication response message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); } else if (station) { capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress); wifi_station_delete(station); } } else if (station) { capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", stationaddress); wifi_station_delete(station); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); } } /* */ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int ielength; int responselength; struct ieee80211_ie_items ieitems; struct ieee80211_associationresponse_params ieee80211_params; struct wifi_station* station; uint16_t resultstatuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationrequest)); if (ielength < 0) { capwap_logging_info("Receive invalid IEEE802.11 Association Request"); return; } /* Get station reference */ station = wifi_station_get(wlan, frame->sa); if (!station) { char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; /* Invalid station, send deauthentication message */ capwap_logging_info("Receive IEEE802.11 Association Request from %s unknown station", capwap_printf_macaddress(buffer, frame->sa, MACADDRESS_EUI48_LENGTH)); wifi_wlan_send_mgmt_deauthentication(wlan, frame->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); return; } /* */ if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED)) { /* Invalid station, send deauthentication message */ capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA, 0); return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationrequest.ie[0], ielength)) { capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); return; } /* */ capwap_logging_info("Receive IEEE802.11 Association Request from %s station", station->addrtext); /* */ if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { /* Verify SSID */ if (ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, NULL) == IEEE80211_VALID_SSID) { station->capability = __le16_to_cpu(frame->associationrequest.capability); station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); if (!ieee80211_aid_create(wlan->aidbitfield, &station->aid)) { /* Get supported rates */ if (!wifi_wlan_get_station_rates(station, &ieitems)) { wifi_wlan_management_legacy_station(wlan, station); resultstatuscode = IEEE80211_STATUS_SUCCESS; } else { resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; } } else { resultstatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; } } else { resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; } /* Create association response packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); memcpy(ieee80211_params.station, frame->sa, ETH_ALEN); ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); ieee80211_params.statuscode = resultstatuscode; ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); ieee80211_params.supportedratescount = wlan->device->supportedratescount; responselength = ieee80211_create_associationresponse_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); if (responselength > 0) { if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); /* Notify association request message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); /* Forwards the association response message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); } else { capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else { capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); /* Station information */ station->capability = __le16_to_cpu(frame->associationresponse.capability); station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); } } /* */ static void wifi_wlan_receive_station_mgmt_reassociation_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int ielength; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationrequest)); if (ielength < 0) { return; } /* TODO */ } /* */ static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int ielength; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); if (ielength < 0) { return; } /* TODO */ /* Notify disassociation message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); } /* */ static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int ielength; struct wifi_station* station; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); if (ielength < 0) { return; } /* Delete station */ station = wifi_station_get(wlan, frame->sa); if (station) { wifi_station_delete(station); } /* Notify deauthentication message also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); } /* */ static void wifi_wlan_receive_station_mgmt_frame(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { int broadcast; /* Check frequency */ if (frequency && (wlan->device->currentfrequency.frequency != frequency)) { return; } /* Check if sent packet to correct AP */ broadcast = ieee80211_is_broadcast_addr(frame->bssid); if (!broadcast && memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { return; } /* */ if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST) { wifi_wlan_receive_station_mgmt_probe_request(wlan, frame, length, rssi, snr, rate); } else if (!memcmp(frame->da, wlan->address, MACADDRESS_EUI48_LENGTH)) { switch (framecontrol_subtype) { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { wifi_wlan_receive_station_mgmt_authentication(wlan, frame, length, rssi, snr, rate); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { wifi_wlan_receive_station_mgmt_association_request(wlan, frame, length, rssi, snr, rate); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { wifi_wlan_receive_station_mgmt_reassociation_request(wlan, frame, length, rssi, snr, rate); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { wifi_wlan_receive_station_mgmt_disassociation(wlan, frame, length, rssi, snr, rate); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { wifi_wlan_receive_station_mgmt_deauthentication(wlan, frame, length, rssi, snr, rate); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { /* TODO */ break; } } } } /* */ static void wifi_wlan_receive_station_mgmt_authentication_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { uint16_t algorithm; uint16_t transactionseqnumber; uint16_t statuscode; struct wifi_station* station; /* Check packet */ if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->authetication)))) { return; } /* Get station information */ station = wifi_station_get(wlan, frame->da); if (!station) { return; } /* */ statuscode = __le16_to_cpu(frame->authetication.statuscode); if (statuscode == IEEE80211_STATUS_SUCCESS) { algorithm = __le16_to_cpu(frame->authetication.algorithm); transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); /* Check if authenticate */ if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { capwap_logging_info("IEEE802.11 Authentication complete to %s station", station->addrtext); station->flags |= WIFI_STATION_FLAGS_AUTHENTICATED; } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { /* TODO */ } } } /* */ static void wifi_wlan_receive_station_mgmt_association_response_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { uint16_t statuscode; struct wifi_station* station; /* Check packet */ if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)))) { return; } /* Get station information */ station = wifi_station_get(wlan, frame->da); if (!station) { return; } /* */ statuscode = __le16_to_cpu(frame->associationresponse.statuscode); if (statuscode == IEEE80211_STATUS_SUCCESS) { capwap_logging_info("IEEE802.11 Association complete to %s station", station->addrtext); /* */ station->flags |= WIFI_STATION_FLAGS_ASSOCIATE; if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { /* Apply authorization if Station already authorized */ if (wlan->device->instance->ops->station_authorize(wlan, station)) { wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } } } /* */ static void wifi_wlan_receive_station_mgmt_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, int ack) { /* Ignore packet if not sent to AP */ if (memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { return; } /* */ switch (framecontrol_subtype) { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { wifi_wlan_receive_station_mgmt_authentication_ack(wlan, frame, length, ack); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { wifi_wlan_receive_station_mgmt_association_response_ack(wlan, frame, length, ack); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { /* TODO */ break; } } } /* */ static int wifi_wlan_receive_ac_mgmt_authentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { int ielength; struct wifi_station* station; int forwardframe = 0; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); if (ielength >= 0) { if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { station = wifi_station_get(wlan, frame->da); if (station) { uint16_t statuscode = __le16_to_cpu(frame->authetication.statuscode); if (statuscode == IEEE80211_STATUS_SUCCESS) { uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); /* Get authentication algorithm */ if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY; } } /* */ forwardframe = 1; } } } return forwardframe; } /* */ static int wifi_wlan_receive_ac_mgmt_association_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { int ielength; struct ieee80211_ie_items ieitems; struct wifi_station* station; int forwardframe = 0; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)); if (ielength >= 0) { station = wifi_station_get(wlan, frame->da); if (station) { if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { if (frame->associationresponse.statuscode != IEEE80211_STATUS_SUCCESS) { capwap_logging_info("AC request deauthentication of station: %s", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { uint16_t statuscode = __le16_to_cpu(frame->associationresponse.statuscode); if ((statuscode == IEEE80211_STATUS_SUCCESS) && !ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationresponse.ie[0], ielength)) { /* Station information */ station->aid = (__le16_to_cpu(frame->associationresponse.aid) & ~IEEE80211_AID_FIELD); /* Get supported rates */ wifi_wlan_get_station_rates(station, &ieitems); /* */ wifi_wlan_management_legacy_station(wlan, station); /* Assign valid WLAN capability */ frame->associationresponse.capability = __cpu_to_le16(wifi_wlan_check_capability(wlan, wlan->capability)); } /* */ forwardframe = 1; } } } return forwardframe; } /* */ static int wifi_wlan_receive_ac_mgmt_reassociation_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { int ielength; struct wifi_station* station; int forwardframe = 0; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationresponse)); if (ielength >= 0) { if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { station = wifi_station_get(wlan, frame->da); if (station) { /* TODO */ } } } return forwardframe; } /* */ static int wifi_wlan_receive_ac_mgmt_disassociation(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { int ielength; struct wifi_station* station; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); if (ielength < 0) { return 0; } /* */ station = wifi_station_get(wlan, frame->da); if (station) { /* Deautherize station */ if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { station->flags &= ~WIFI_STATION_FLAGS_AUTHORIZED; wlan->device->instance->ops->station_deauthorize(wlan, station->address); } /* Deassociate station */ station->flags &= ~WIFI_STATION_FLAGS_ASSOCIATE; } return 1; } /* */ static int wifi_wlan_receive_ac_mgmt_deauthentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { int ielength; struct wifi_station* station; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); if (ielength < 0) { return 0; } /* Delete station */ station = wifi_station_get(wlan, frame->da); if (station) { wifi_station_delete(station); } return 1; } /* */ static int wifi_wlan_receive_ac_mgmt_frame(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype) { int forwardframe = 0; switch (framecontrol_subtype) { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { forwardframe = wifi_wlan_receive_ac_mgmt_authentication(wlan, frame, length); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { forwardframe = wifi_wlan_receive_ac_mgmt_association_response(wlan, frame, length); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { forwardframe = wifi_wlan_receive_ac_mgmt_reassociation_response(wlan, frame, length); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { forwardframe = wifi_wlan_receive_ac_mgmt_disassociation(wlan, frame, length); break; } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { forwardframe = wifi_wlan_receive_ac_mgmt_deauthentication(wlan, frame, length); break; } } return forwardframe; } /* */ int wifi_driver_init(struct capwap_timeout* timeout) { int i; ASSERT(timeout != NULL); /* Socket utils */ memset(&g_wifiglobal, 0, sizeof(struct wifi_global)); g_wifiglobal.sock_util = socket(AF_PACKET, SOCK_RAW, 0); if (g_wifiglobal.sock_util < 0) { return -1; } /* Initialize driver */ for (i = 0; wifi_driver[i].ops != NULL; i++) { wifi_driver[i].handle = wifi_driver[i].ops->global_init(); if (!wifi_driver[i].handle) { close(g_wifiglobal.sock_util); return -1; } } /* */ g_wifiglobal.timeout = timeout; g_wifiglobal.devices = capwap_list_create(); g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE, WIFI_STATIONS_KEY_SIZE, wifi_hash_station_gethash, NULL, wifi_hash_station_free); return 0; } /* */ void wifi_driver_free(void) { int i; struct capwap_list_item* itemdevice; /* Free devices */ if (g_wifiglobal.devices) { for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { struct wifi_device* device = (struct wifi_device*)itemdevice->item; /* Free WLANS */ if (device->wlans) { while (device->wlans->first) { wifi_wlan_destroy((struct wifi_wlan*)device->wlans->first->item); } capwap_list_free(device->wlans); } /* */ if (device->handle) { device->instance->ops->device_deinit(device); } /* Free capability */ if (device->capability) { if (device->capability->bands) { for (i = 0; i < device->capability->bands->count; i++) { struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(device->capability->bands, i); if (bandcap->freq) { capwap_array_free(bandcap->freq); } if (bandcap->rate) { capwap_array_free(bandcap->rate); } } capwap_array_free(device->capability->bands); } if (device->capability->ciphers) { capwap_array_free(device->capability->ciphers); } capwap_free(device->capability); } } capwap_list_free(g_wifiglobal.devices); } /* Free stations */ if (g_wifiglobal.stations) { capwap_hash_free(g_wifiglobal.stations); } /* Free driver */ for (i = 0; wifi_driver[i].ops != NULL; i++) { wifi_driver[i].ops->global_deinit(wifi_driver[i].handle); } /* */ close(g_wifiglobal.sock_util); } /* */ int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { int i; int result = 0; struct capwap_list_item* itemdevice; struct capwap_list_item* itemwlan; if ((count > 0) && (!fds || !events)) { return -1; } /* Get from driver */ for (i = 0; wifi_driver[i].ops != NULL; i++) { result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); } /* Get from device */ for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { struct wifi_device* device = (struct wifi_device*)itemdevice->item; if (device->handle) { result += device->instance->ops->device_getfdevent(device, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); /* Get from wlan */ if (device->wlans) { for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; if (wlan->handle) { result += device->instance->ops->wlan_getfdevent(wlan, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); } } } } } return result; } /* */ struct wifi_wlan* wifi_get_wlan(uint32_t ifindex) { struct capwap_list_item* itemdevice; struct capwap_list_item* itemwlan; ASSERT(g_wifiglobal.devices != NULL); ASSERT(ifindex > 0); /* Search device */ for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { struct wifi_device* device = (struct wifi_device*)itemdevice->item; /* Search wlan */ if (device->wlans) { for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; if (wlan->virtindex == ifindex) { return wlan; } } } } return NULL; } /* */ struct wifi_device* wifi_device_connect(const char* ifname, const char* driver) { int i; int length; struct capwap_list_item* itemdevice; struct wifi_device* device = NULL; ASSERT(ifname != NULL); ASSERT(driver != NULL); /* Check */ length = strlen(ifname); if ((length <= 0) || (length >= IFNAMSIZ)) { capwap_logging_warning("Wifi device name error: %s", ifname); return NULL; } /* Search driver */ for (i = 0; wifi_driver[i].ops != NULL; i++) { if (!strcmp(driver, wifi_driver[i].ops->name)) { itemdevice = capwap_itemlist_create(sizeof(struct wifi_device)); device = (struct wifi_device*)itemdevice->item; memset(device, 0, sizeof(struct wifi_device)); /* */ device->global = &g_wifiglobal; device->instance = &wifi_driver[i]; strcpy(device->phyname, ifname); /* Device init */ if (!wifi_driver[i].ops->device_init(wifi_driver[i].handle, device)) { /* Registered new device */ device->wlans = capwap_list_create(); /* Device capability */ device->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability)); memset(device->capability, 0, sizeof(struct wifi_capability)); device->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1); device->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1); /* Retrieve device capability */ device->instance->ops->device_getcapability(device, device->capability); /* Appent to device list */ capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice); } else { capwap_itemlist_free(itemdevice); device = NULL; } break; } } return device; } /* */ const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device) { ASSERT(device != NULL); ASSERT(device->handle != NULL); return device->capability; } /* */ int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params) { ASSERT(device != NULL); ASSERT(device->handle != NULL); ASSERT(params != NULL); /* */ device->flags |= WIFI_DEVICE_SET_CONFIGURATION; device->beaconperiod = params->beaconperiod; device->dtimperiod = params->dtimperiod; device->shortpreamble = (params->shortpreamble ? 1 : 0); /* Update beacons */ if (device->wlans->count) { device->instance->ops->device_updatebeacons(device); } return 0; } /* */ int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel) { int i, j; int result = -1; const struct wifi_capability* capability; uint32_t frequency = 0; ASSERT(device != NULL); ASSERT(device->handle != NULL); /* Capability device */ capability = wifi_device_getcapability(device); if (!capability || !(capability->flags & WIFI_CAPABILITY_RADIOTYPE) || !(capability->flags & WIFI_CAPABILITY_BANDS)) { return -1; } /* Search frequency */ for (i = 0; (i < capability->bands->count) && !frequency; i++) { struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); if (bandcap->band == band) { for (j = 0; j < bandcap->freq->count; j++) { struct wifi_freq_capability* freqcap = (struct wifi_freq_capability*)capwap_array_get_item_pointer(bandcap->freq, j); if (freqcap->channel == channel) { frequency = freqcap->frequency; break; } } } } /* Configure frequency */ if (frequency) { device->currentfrequency.band = band; device->currentfrequency.mode = mode; device->currentfrequency.channel = channel; device->currentfrequency.frequency = frequency; /* According to the selected band remove the invalid mode */ if (device->currentfrequency.band == WIFI_BAND_2GHZ) { device->currentfrequency.mode &= ~CAPWAP_RADIO_TYPE_80211A; } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { device->currentfrequency.mode &= ~(CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G); } /* Set frequency */ device->flags |= WIFI_DEVICE_SET_FREQUENCY; result = device->instance->ops->device_setfrequency(device); } /* */ return result; } /* */ int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount) { struct device_setrates_params buildrate; ASSERT(device != NULL); ASSERT(device->handle != NULL); ASSERT(rates != NULL); ASSERT(ratescount > 0); /* */ wifi_wlan_getrates(device, rates, ratescount, &buildrate); if (!buildrate.supportedratescount || (buildrate.supportedratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { return -1; } else if (!buildrate.basicratescount || (buildrate.basicratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { return -1; } /* Set new rates */ device->flags |= WIFI_DEVICE_SET_RATES; memcpy(device->supportedrates, buildrate.supportedrates, buildrate.supportedratescount); device->supportedratescount = buildrate.supportedratescount; memcpy(device->basicrates, buildrate.basicrates, buildrate.basicratescount); device->basicratescount = buildrate.basicratescount; /* Update beacons */ if (device->wlans->count) { device->instance->ops->device_updatebeacons(device); } return 0; } /* */ struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname) { int length; struct wifi_wlan* wlan; struct capwap_list_item* itemwlan; ASSERT(device != NULL); ASSERT(device->handle != NULL); ASSERT(ifname != NULL); /* Check */ length = strlen(ifname); if ((length <= 0) || (length >= IFNAMSIZ)) { capwap_logging_warning("Wifi device name error: %s", ifname); return NULL; } /* Create new WLAN */ itemwlan = capwap_itemlist_create(sizeof(struct wifi_wlan)); wlan = (struct wifi_wlan*)itemwlan->item; memset(wlan, 0, sizeof(struct wifi_wlan)); /* */ wlan->device = device; strcpy(wlan->virtname, ifname); wlan->maxstationscount = IEEE80211_MAX_STATIONS; /* Appent to wlan list */ capwap_itemlist_insert_after(device->wlans, NULL, itemwlan); /* Create interface */ wlan->handle = device->instance->ops->wlan_create(device, wlan); if (!wlan->handle) { capwap_logging_warning("Unable to create virtual interface: %s", ifname); wifi_wlan_destroy(wlan); return NULL; } /* Interface info */ wlan->virtindex = wifi_iface_index(ifname); if (wifi_iface_hwaddr(g_wifiglobal.sock_util, wlan->virtname, wlan->address)) { capwap_logging_warning("Unable to get macaddress: %s", ifname); wifi_wlan_destroy(wlan); return NULL; } return wlan; } /* */ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params) { int result; ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); ASSERT(params != NULL); /* Check device */ if ((wlan->flags & WIFI_WLAN_RUNNING) || ((wlan->device->flags & WIFI_DEVICE_REQUIRED_FOR_BSS) != WIFI_DEVICE_REQUIRED_FOR_BSS)) { return -1; } /* Save configuration */ strcpy(wlan->ssid, params->ssid); wlan->ssid_hidden = params->ssid_hidden; wlan->capability = params->capability; wlan->authmode = params->authmode; wlan->macmode = params->macmode; wlan->tunnelmode = params->tunnelmode; wlan->radioid = params->radioid; wlan->wlanid = params->wlanid; /* Start AP */ result = wlan->device->instance->ops->wlan_startap(wlan); if (!result) { wlan->device->wlanactive++; capwap_logging_info("Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid); } else { wifi_wlan_stopap(wlan); } return result; } /* */ void wifi_wlan_stopap(struct wifi_wlan* wlan) { ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); /* Stop AP */ wlan->device->instance->ops->wlan_stopap(wlan); /* */ if (wlan->flags & WIFI_WLAN_RUNNING) { wlan->device->wlanactive--; } /* */ wlan->flags = 0; /* TODO: Remove all stations from hash */ } /* */ int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid) { ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); ASSERT(bssid != NULL); memcpy(bssid, wlan->address, MACADDRESS_EUI48_LENGTH); return 0; } /* */ uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability) { uint16_t result = capability; /* Force ESS capability */ result |= IEEE80211_CAPABILITY_ESS; /* Check short preamble capability */ if (wlan->device->shortpreamble && !wlan->device->stationsnoshortpreamblecount) { result |= IEEE80211_CAPABILITY_SHORTPREAMBLE; } else { result &= ~IEEE80211_CAPABILITY_SHORTPREAMBLE; } /* Check privacy capability */ /* TODO */ /* Check short slot time capability */ if ((wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) && !wlan->device->stationsnoshortslottimecount) { result |= IEEE80211_CAPABILITY_SHORTSLOTTIME; } else { result &= ~IEEE80211_CAPABILITY_SHORTSLOTTIME; } return capability; } /* */ void wifi_wlan_destroy(struct wifi_wlan* wlan) { struct capwap_list_item* itemwlan; ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); /* Terminate service */ wifi_wlan_stopap(wlan); /* */ wlan->device->instance->ops->wlan_delete(wlan); /* Remove wlan from device's list */ for (itemwlan = wlan->device->wlans->first; itemwlan; itemwlan = itemwlan->next) { if (wlan == (struct wifi_wlan*)itemwlan->item) { capwap_itemlist_free(capwap_itemlist_remove(wlan->device->wlans, itemwlan)); break; } } } /* */ void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { uint16_t framecontrol; uint16_t framecontrol_type; uint16_t framecontrol_subtype; ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; } /* Get type frame */ framecontrol = __le16_to_cpu(frame->framecontrol); framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); /* Parsing frame */ if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { wifi_wlan_receive_station_mgmt_frame(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, frequency, rssi, snr, rate); } } /* */ void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack) { uint16_t framecontrol; uint16_t framecontrol_type; uint16_t framecontrol_subtype; ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; } /* Get type frame */ framecontrol = __le16_to_cpu(frame->framecontrol); framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); /* Parsing frame */ if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { wifi_wlan_receive_station_mgmt_ackframe(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, ack); } } /* */ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length) { int forwardframe = 1; uint16_t framecontrol; uint16_t framecontrol_type; uint16_t framecontrol_subtype; ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; } /* Get type frame */ framecontrol = __le16_to_cpu(frame->framecontrol); framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); /* Parsing frame */ if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { forwardframe = wifi_wlan_receive_ac_mgmt_frame(wlan, (struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype); } /* Forward frame */ if (forwardframe) { int nowaitack = (ieee80211_is_broadcast_addr(ieee80211_get_da_addr(frame)) ? 1 : 0); wlan->device->instance->ops->wlan_sendframe(wlan, (uint8_t*)frame, length, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack); } } /* */ int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { int result; ASSERT(wlan != NULL); ASSERT(wlan->handle != NULL); if (!data || (length <= 0)) { return -1; } /* Send packet to AC */ result = wtp_kmod_send_data(wlan->radioid, data, length, rssi, snr, rate); if (result) { capwap_logging_warning("Unable to sent packet to AC: %d error code", result); } return result; } /* */ int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params) { int result; struct wifi_station* station; ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); ASSERT(params != NULL); /* Get station */ station = wifi_station_get(wlan, params->address); if (!station) { return -1; } else if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { return 0; } /* */ capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; /* Station is authorized only after Authentication and Association */ station->flags |= WIFI_STATION_FLAGS_AUTHORIZED; if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) || !(station->flags & WIFI_STATION_FLAGS_ASSOCIATE)) { return 0; } /* Station authorized */ result = wlan->device->instance->ops->station_authorize(wlan, station); if (result) { wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } return result; } /* */ void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) { struct wifi_station* station; ASSERT(device != NULL); ASSERT(address != NULL); /* */ station = wifi_station_get(NULL, address); if (station && station->wlan) { wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } /* */ uint32_t wifi_iface_index(const char* ifname) { if (!ifname || !*ifname) { return 0; } return if_nametoindex(ifname); } /* */ int wifi_iface_getstatus(int sock, const char* ifname) { struct ifreq ifreq; ASSERT(sock > 0); ASSERT(ifname != NULL); ASSERT(*ifname != 0); /* Change link state of interface */ memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, ifname); if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { return ((ifreq.ifr_flags & IFF_UP) ? 1: 0); } return -1; } /* */ int wifi_iface_updown(int sock, const char* ifname, int up) { struct ifreq ifreq; ASSERT(sock > 0); ASSERT(ifname != NULL); ASSERT(*ifname != 0); /* Change link state of interface */ memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, ifname); if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { /* Set flag */ if (up) { if (ifreq.ifr_flags & IFF_UP) { return 0; /* Flag is already set */ } ifreq.ifr_flags |= IFF_UP; } else { if (!(ifreq.ifr_flags & IFF_UP)) { return 0; /* Flag is already unset */ } ifreq.ifr_flags &= ~IFF_UP; } if (!ioctl(sock, SIOCSIFFLAGS, &ifreq)) { return 0; } } return -1; } /* */ int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr) { struct ifreq ifreq; ASSERT(sock > 0); ASSERT(ifname != NULL); ASSERT(*ifname != 0); ASSERT(hwaddr != NULL); /* Get mac address of interface */ memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, ifname); if (!ioctl(sock, SIOCGIFHWADDR, &ifreq)) { if (ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) { memcpy(hwaddr, ifreq.ifr_hwaddr.sa_data, MACADDRESS_EUI48_LENGTH); return 0; } } return -1; } /* */ int wifi_frequency_to_radiotype(uint32_t freq) { if ((freq >= 2412) && (freq <= 2472)) { return CAPWAP_RADIO_TYPE_80211G; } else if (freq == 2484) { return CAPWAP_RADIO_TYPE_80211B; } else if ((freq >= 4915) && (freq <= 4980)) { return CAPWAP_RADIO_TYPE_80211A; } else if ((freq >= 5035) && (freq <= 5825)) { return CAPWAP_RADIO_TYPE_80211A; } return -1; }