#include "wtp.h" #include "list.h" #include "hash.h" #include "element.h" #include "wifi_drivers.h" #include "radio.h" #include "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 /* Wifi Manager */ static struct wifi_global g_wifiglobal; static uint8_t g_bufferIEEE80211[IEEE80211_MTU]; /* */ static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode); static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode); static void wifi_wlan_disassociate_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode); static void wifi_wlan_send_mgmt_disassociation(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode); /* device operations */ static int device_init(struct wifi_driver_instance *instance, struct wifi_device* device) { return instance->ops->device_init(instance->handle, device); } static int device_getcapability(struct wifi_device* device, struct wifi_capability* capability) { return device->instance->ops->device_getcapability(device, device->capability); } static void device_updatebeacons(struct wifi_device* device) { device->instance->ops->device_updatebeacons(device); } static int device_setfrequency(struct wifi_device* device) { return device->instance->ops->device_setfrequency(device); } static int device_settxqueue(struct wifi_device* device, int queue, int aifs, int cw_min, int cw_max, int txop) { return device->instance->ops->device_settxqueue(device, queue, aifs, cw_min, cw_max, txop); } static void device_deinit(struct wifi_device* device) { if (device->handle) device->instance->ops->device_deinit(device); device->handle = NULL; } static wifi_wlan_handle wlan_create(struct wifi_device* device, struct wifi_wlan* wlan) { return wlan->device->instance->ops->wlan_create(device, wlan); } static int wlan_startap(struct wifi_wlan* wlan) { return wlan->device->instance->ops->wlan_startap(wlan); } static void wlan_stopap(struct wifi_wlan* wlan) { wlan->device->instance->ops->wlan_stopap(wlan); } static int wlan_sendframe(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack) { return wlan->device->instance->ops->wlan_sendframe(wlan, frame, length, frequency, duration, offchannel_tx_ok, no_cck_rate, no_wait_ack); } static void wlan_poll_station(struct wifi_wlan* wlan, const uint8_t* address, int qos) { wlan->device->instance->ops->wlan_poll_station(wlan, address, qos); } static void wlan_delete(struct wifi_wlan* wlan) { wlan->device->instance->ops->wlan_delete(wlan); } static int wlan_set_key(struct wifi_wlan* wlan, uint32_t alg, const uint8_t *addr, int key_idx, int set_tx, const uint8_t *seq, size_t seq_len, const uint8_t *key, size_t key_len) { return wlan->device->instance->ops->wlan_set_key(wlan, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } static int station_authorize(struct wifi_wlan* wlan, struct wifi_station* station) { return wlan->device->instance->ops->station_authorize(wlan, station); } static int station_deauthorize(struct wifi_wlan* wlan, const uint8_t* address) { return wlan->device->instance->ops->station_deauthorize(wlan, address); } static int station_get_inact_sec(struct wifi_wlan* wlan, const uint8_t* address) { return wlan->device->instance->ops->station_get_inact_sec(wlan, address); } /* */ static 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; } /* */ 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) { log_printf(LOG_DEBUG, "getrates: getcapability failed"); return; } /* Get radio type for basic rate */ radiotype = wifi_frequency_to_radiotype(device->currentfrequency.frequency); if (radiotype < 0) { log_printf(LOG_DEBUG, "getrates: no radiotype for freq %d", device->currentfrequency.frequency); return; } log_printf(LOG_DEBUG, "getrates: radiotype %d, freq: %d", radiotype, device->currentfrequency.frequency); log_printf(LOG_DEBUG, "getrates: Band %d", device->currentfrequency.band); /* 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; } } } log_printf(LOG_DEBUG, "getrates: Mode %d", mode); #if 0 /* WTF: the AC should know what it's doing and set those rate when it want's them */ /* 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; } #endif log_printf(LOG_DEBUG, "getrates: Bands Count %lu", capability->bands->count); /* 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); log_printf(LOG_DEBUG, "getrates: Bandcap Band %lu", bandcap->band); if (bandcap->band != device->currentfrequency.band) continue; 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++) { int is_basic = 0; switch (mode) { case CAPWAP_RADIO_TYPE_80211A: is_basic = IS_IEEE80211_BASICRATE_A(device_params->supportedrates[i]); break; case CAPWAP_RADIO_TYPE_80211B: is_basic = IS_IEEE80211_BASICRATE_B(device_params->supportedrates[i]); break; case CAPWAP_RADIO_TYPE_80211G: is_basic = IS_IEEE80211_BASICRATE_G(device_params->supportedrates[i]); break; case CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G: is_basic = IS_IEEE80211_BASICRATE_BG(device_params->supportedrates[i]); break; } if (is_basic) { 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 hashsize) { uint8_t* macaddress = (uint8_t*)key; return ((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]); } /* */ static const void* wifi_hash_station_getkey(const void* data) { return (const void*)((struct wifi_station*)data)->address; } /* */ static int wifi_hash_station_cmp(const void* key1, const void* key2) { return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); } /* */ static void wifi_hash_station_free(void* data) { struct wifi_station* station = (struct wifi_station*)data; ASSERT(data != NULL); /* */ log_printf(LOG_INFO, "Destroy station: " MACSTR, MAC2STR(station->address)); 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) 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) device_updatebeacons(wlan->device); /* Disconnet from WLAN */ wlan->stationscount--; station->wlan = NULL; } /* Remove timers */ ev_timer_stop(EV_DEFAULT_UC_ &station->timeout); /* */ station->flags = 0; station->supportedratescount = 0; } /* */ static void wifi_station_schedule_delete(struct wifi_station* station) { ASSERT(station != NULL); /* */ log_printf(LOG_INFO, "Schedule Delete station: " MACSTR, MAC2STR(station->address)); /* Delay delete station */ station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DELETE; station->timeout.repeat = WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED / 1000.0; ev_timer_again(EV_DEFAULT_UC_ &station->timeout); } /* */ static void wifi_station_delete(struct wifi_station* station) { ASSERT(station != NULL); /* */ log_printf(LOG_INFO, "Delete station: " MACSTR, MAC2STR(station->address)); /* Free station into hash callback function */ wifi_station_clean(station); capwap_hash_delete(g_wifiglobal.stations, station->address); } /* */ static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const uint8_t* address) { struct wifi_station* station; ASSERT(wlan != NULL); ASSERT(address != NULL); /* */ station = wifi_station_get(NULL, address); if (station) { wtp_kmod_del_station(wlan->radioid, address); if (station->wlan && (station->wlan != wlan)) { log_printf(LOG_INFO, "Roaming station: " MACSTR, MAC2STR(address)); if (station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) wifi_wlan_send_mgmt_deauthentication(station->wlan, address, IEEE80211_REASON_PREV_AUTH_NOT_VALID); } log_printf(LOG_INFO, "Reuse station: " MACSTR, MAC2STR(address)); wifi_station_clean(station); } /* Checks if it has reached the maximum number of stations */ if (wlan->stationscount >= wlan->maxstationscount) { log_printf(LOG_WARNING, "Unable create station: reached the maximum number of stations"); return NULL; } /* Create new station */ if (!station) { log_printf(LOG_INFO, "Create new station: " MACSTR, MAC2STR(address)); /* */ 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); /* Add to pool */ capwap_hash_add(g_wifiglobal.stations, 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; /* 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) { log_printf(LOG_WARNING, "Unable to create IEEE802.11 Deauthentication " "to " MACSTR " station", MAC2STR(station)); return; } if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { log_printf(LOG_WARNING, "Unable to send IEEE802.11 Deauthentication " "to " MACSTR " station", MAC2STR(station)); return; } log_printf(LOG_INFO, "Sent IEEE802.11 Deauthentication to " MACSTR " station", MAC2STR(station)); /* Forwards the station deauthentication also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); } /* */ static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode) { 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); /* delete station */ wifi_station_schedule_delete(station); } /* */ static void wifi_wlan_send_mgmt_disassociation(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode) { int responselength; struct ieee80211_disassociation_params ieee80211_params; /* Create disassociation packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_disassociation_params)); memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); memcpy(ieee80211_params.station, station, ETH_ALEN); ieee80211_params.reasoncode = reasoncode; responselength = ieee80211_create_disassociation(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); if (responselength < 0) { log_printf(LOG_WARNING, "Unable to create IEEE802.11 Disassociation " "to " MACSTR " station", MAC2STR(station)); return; } if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { log_printf(LOG_WARNING, "Unable to send IEEE802.11 Disassociation " "to " MACSTR " station", MAC2STR(station)); return; } log_printf(LOG_INFO, "Sent IEEE802.11 Disassociation to " MACSTR " station", MAC2STR(station)); /* Forward the station disassociation also to AC */ wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); } /* */ static void wifi_wlan_disassociate_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode) { ASSERT(wlan != NULL); ASSERT(station != NULL); /* Send deauthentication message */ if (station->flags & WIFI_STATION_FLAGS_ASSOCIATE) wifi_wlan_send_mgmt_disassociation(wlan, station->address, reasoncode); } /* */ static void wifi_wlan_poll_station(struct wifi_wlan* wlan, struct wifi_station* station) { ASSERT(wlan != NULL); ASSERT(station != NULL); wlan_poll_station(wlan, station->address, station->flags & WIFI_STATION_FLAGS_WMM); } /* */ static void wifi_station_timeout(EV_P_ ev_timer *w, int revents) { struct wifi_station *station = (struct wifi_station *) (((char *)w) - offsetof(struct wifi_station, timeout)); struct wifi_wlan* wlan = (struct wifi_wlan *)w->data; unsigned long repeat = 0; log_printf(LOG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_action=%d", wlan->virtname, __func__, MAC2STR(station->address), station->flags, station->timeout_action); if (station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DELETE) { wifi_station_delete(station); return; } if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) && station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC) { int inactive_sec; inactive_sec = station_get_inact_sec(wlan, station->address); log_printf(LOG_WARNING, "Station " MACSTR ", inactive for %d seconds", MAC2STR(station->address), inactive_sec); if (inactive_sec == -1) { log_printf(LOG_DEBUG, "Check inactivity: Could not get station info " "from kernel driver for " MACSTR, MAC2STR(station->address)); repeat = station->max_inactivity; } else if (inactive_sec == -ENOENT) { log_printf(LOG_DEBUG, "Station " MACSTR " has lost its driver entry", MAC2STR(station->address)); /* Avoid sending client probe on removed client */ station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE; goto skip_poll; } else if (inactive_sec < station->max_inactivity) { /* station activity detected; reset timeout state */ log_printf(LOG_DEBUG, "Station " MACSTR " has been active %is ago", MAC2STR(station->address), inactive_sec); station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC; repeat = station->max_inactivity - inactive_sec; log_printf(LOG_DEBUG, "Station " MACSTR " has been inactive for: %d sec, max allowed: %d", MAC2STR(station->address), inactive_sec, station->max_inactivity); } else { log_printf(LOG_DEBUG, "Station " MACSTR " has been inactive too " "long: %d sec, max allowed: %d", MAC2STR(station->address), inactive_sec, station->max_inactivity); } } if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) && station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE && !(station->flags & WIFI_STATION_FLAGS_POLL_PENDING)) { log_printf(LOG_DEBUG, "Station " MACSTR " has ACKed data poll", MAC2STR(station->address)); /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC; repeat = station->max_inactivity; } skip_poll: if (repeat) { log_printf(LOG_DEBUG, "%s: register wifi_station_timeout for " MACSTR " (%lu seconds)", __func__, MAC2STR(station->address), repeat); w->repeat = repeat; ev_timer_again(EV_A_ w); return; } if ((station->flags & WIFI_STATION_FLAGS_ASSOCIATE) && station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC) { log_printf(LOG_DEBUG, " Polling STA"); station->flags |= WIFI_STATION_FLAGS_POLL_PENDING; wifi_wlan_poll_station(wlan, station); } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { /* everything else means we go to remove the Station */ int deauth = station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; log_printf(LOG_DEBUG, "Timeout, sending %s info to STA " MACSTR, deauth ? "deauthentication" : "disassociation", MAC2STR(station->address)); if (deauth) { wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); } else { uint16_t reason = (station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE) ? IEEE80211_REASON_DISASSOC_DUE_TO_INACTIVITY : IEEE80211_REASON_PREV_AUTH_NOT_VALID; wifi_wlan_disassociate_station(wlan, station, reason); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT && station->timeout_action == WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE) { /* * TODO: tell the AC about the STA timeout with a WTP Event */ } switch (station->timeout_action) { case WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC: station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE; w->repeat = WIFI_STATION_TIMEOUT_BEFORE_DISASSOCIATE / 1000.0; log_printf(LOG_DEBUG, "%s: register ap_handle_timer timeout for " MACSTR " (%f seconds - TIMEOUT_BEFORE_DISASSOCIATE)", __func__, MAC2STR(station->address), w->repeat); ev_timer_again(EV_A_ w); break; case WIFI_STATION_TIMEOUT_ACTION_DISASSOCIATE: station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; w->repeat = WIFI_STATION_TIMEOUT_BEFORE_DEAUTHENTICATE / 1000.0; log_printf(LOG_DEBUG, "%s: register ap_handle_timer timeout for " MACSTR " (%f seconds - TIMEOUT_BEFORE_DEAUTHENTICATE)", __func__, MAC2STR(station->address), w->repeat); ev_timer_again(EV_A_ w); break; case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: log_printf(LOG_DEBUG, MACSTR " deauthenticated due to inactivity (timer DEAUTH/REMOVE)", MAC2STR(station->address)); break; default: break; } } /* */ void wifi_wlan_client_probe_event(struct wifi_wlan *wlan, const uint8_t *address) { struct wifi_station* station; station = wifi_station_get(wlan, address); if (!station) return; if (!(station->flags & WIFI_STATION_FLAGS_POLL_PENDING)) return; log_printf(LOG_DEBUG, "STA " MACSTR " ACKed pending " "activity poll", MAC2STR(station->address)); station->flags &= ~WIFI_STATION_FLAGS_POLL_PENDING; } /* */ 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 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)) { log_printf(LOG_DEBUG, "Could not parse ProbeReq from " MACSTR, MAC2STR(frame->sa)); return; } /* Validate Probe Request Packet */ if (!ieitems.ssid || !ieitems.supported_rates) { log_printf(LOG_DEBUG, "STA " MACSTR " sent probe request " "without SSID or supported rates element", MAC2STR(frame->sa)); return; } /* Don't reply to Probe Requests on an adjacent channel. */ if (ieitems.dsss && (wlan->device->currentfrequency.mode & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G)) && wlan->device->currentfrequency.channel != ieitems.dsss->channel) { log_printf(LOG_DEBUG, "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u", wlan->device->currentfrequency.channel, ieitems.dsss->channel); return; } /* Verify the SSID */ ssidcheck = ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, ieitems.ssid_list); switch (ssidcheck) { case IEEE80211_WRONG_SSID: return; case IEEE80211_WILDCARD_SSID: if (wlan->ssid_hidden) { log_printf(LOG_DEBUG, "Probe Request from " MACSTR " for " "broadcast SSID ignored", MAC2STR(frame->sa)); return; } break; default: break; } /* Create probe response */ memset(¶ms, 0, sizeof(struct ieee80211_probe_response_params)); memcpy(params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); memcpy(params.station, frame->sa, MACADDRESS_EUI48_LENGTH); params.beaconperiod = wlan->device->beaconperiod; params.capability = wifi_wlan_check_capability(wlan, wlan->capability); params.ssid = wlan->ssid; memcpy(params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); params.supportedratescount = wlan->device->supportedratescount; params.mode = wlan->device->currentfrequency.mode; params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); params.channel = wlan->device->currentfrequency.channel; params.response_ies = wlan->response_ies; params.response_ies_len = wlan->response_ies_len; responselength = ieee80211_create_probe_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), ¶ms); if (responselength < 0) return; /* Send probe response */ nowaitack = ((ssidcheck == IEEE80211_WILDCARD_SSID) && ieee80211_is_broadcast_addr(frame->da) ? 1 : 0); if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { log_printf(LOG_WARNING, "Unable to send IEEE802.11 Probe Response"); return; } /* 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); } /* */ 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) 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; if (ieitems->extended_supported_rates && (ieitems->supported_rates->len + ieitems->extended_supported_rates->len) > 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; uint16_t responsestatuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); if (ielength < 0) { log_printf(LOG_INFO, "Receive invalid IEEE802.11 Authentication Request"); return; } /* Ignore authentication packet from same AP */ if (!memcmp(frame->sa, wlan->address, MACADDRESS_EUI48_LENGTH)) { log_printf(LOG_INFO, "Ignore IEEE802.11 Authentication Request from same AP"); return; } /* Get ACL Station */ acl = wtp_radio_acl_station(frame->sa); if (acl == WTP_RADIO_ACL_STATION_DENY) { log_printf(LOG_INFO, "Denied IEEE802.11 Authentication Request " "from " MACSTR " station", MAC2STR(frame->sa)); return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->authetication.ie[0], ielength)) { log_printf(LOG_INFO, "Invalid IEEE802.11 Authentication Request " "from " MACSTR " station", MAC2STR(frame->sa)); return; } /* */ log_printf(LOG_INFO, "Receive IEEE802.11 Authentication Request " "from " MACSTR " station", MAC2STR(frame->sa)); /* 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 */ ev_timer_stop(EV_DEFAULT_UC_ &station->timeout); ev_timer_init(&station->timeout, wifi_station_timeout, WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE / 1000.0, 0.); station->timeout.data = wlan; station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; ev_timer_start(EV_DEFAULT_UC_ &station->timeout); 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) { log_printf(LOG_WARNING, "Unable to create IEEE802.11 Authentication Response " "to " MACSTR " station", MAC2STR(frame->sa)); goto out_delete_station; } /* Send authentication response */ if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { log_printf(LOG_WARNING, "Unable to send IEEE802.11 Authentication Response " "to " MACSTR " station", MAC2STR(frame->sa)); goto out_delete_station; } log_printf(LOG_INFO, "Sent IEEE802.11 Authentication Response " "to " MACSTR " station with %d status code", MAC2STR(frame->sa), (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 (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); return; out_delete_station: if (station) wifi_station_delete(station); return; } /* */ 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 params; struct wifi_station* station; uint16_t resultstatuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationrequest)); if (ielength < 0) { log_printf(LOG_INFO, "Receive invalid IEEE802.11 Association Request"); return; } /* Get station reference */ station = wifi_station_get(wlan, frame->sa); if (!station) { /* Invalid station, send deauthentication message */ log_printf(LOG_INFO, "Receive IEEE802.11 Association Request " "from " MACSTR " unknown station", MAC2STR(frame->sa)); 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 */ log_printf(LOG_INFO, "Receive IEEE802.11 Association Request " "from " MACSTR " unauthorized station", MAC2STR(station->address)); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); return; } /* Parsing Information Elements */ if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationrequest.ie[0], ielength)) { log_printf(LOG_INFO, "Invalid IEEE802.11 Association Request " "from " MACSTR " station", MAC2STR(station->address)); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); return; } /* */ log_printf(LOG_INFO, "Receive IEEE802.11 Association Request " "from " MACSTR " station", MAC2STR(station->address)); if (ieitems.wmm_ie != NULL && ieitems.wmm_ie->version == 1) { station->flags |= WIFI_STATION_FLAGS_WMM; station->qosinfo = ieitems.wmm_ie->qos_info; } /* */ switch(wlan->macmode) { case 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(¶ms, 0, sizeof(struct ieee80211_associationresponse_params)); memcpy(params.bssid, wlan->address, ETH_ALEN); memcpy(params.station, frame->sa, ETH_ALEN); params.capability = wifi_wlan_check_capability(wlan, wlan->capability); params.statuscode = resultstatuscode; params.aid = IEEE80211_AID_FIELD | station->aid; memcpy(params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); params.supportedratescount = wlan->device->supportedratescount; params.response_ies = wlan->response_ies; params.response_ies_len = wlan->response_ies_len; responselength = ieee80211_create_associationresponse_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), ¶ms); if (responselength < 0) { log_printf(LOG_WARNING, "Unable to create IEEE802.11 Association Response " "to " MACSTR " station", MAC2STR(station->address)); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); break; } if (wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { log_printf(LOG_WARNING, "Unable to send IEEE802.11 Association Response " "to " MACSTR " station", MAC2STR(station->address)); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); } log_printf(LOG_INFO, "Sent IEEE802.11 Association Response " "to " MACSTR " station with %d status code", MAC2STR(station->address), (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); break; case 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); break; } } /* */ 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_action(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { log_hexdump(LOG_DEBUG, "Wifi ACTION FRAME", (uint8_t *)frame, length); 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) != 0) 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) == 0) { 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: wifi_wlan_receive_station_mgmt_action(wlan, frame, length, rssi, snr, rate); 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) return; 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)) { log_printf(LOG_INFO, "IEEE802.11 Authentication complete " "to " MACSTR " station", MAC2STR(station->address)); 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) return; log_printf(LOG_INFO, "IEEE802.11 Association complete " "to " MACSTR " station", MAC2STR(station->address)); /* */ station->flags |= WIFI_STATION_FLAGS_ASSOCIATE; if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { int result; /* Apply authorization if Station already authorized */ result = station_authorize(wlan, station); if (!result) result = wifi_station_set_key(wlan, station); if (result) wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); if (!result) { /* let the timer expire, but set the action to SEND NULLFUNC */ station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC; } } } /* */ 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) != 0) 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; uint16_t statuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); if (ielength < 0) return 0; if (wlan->macmode != CAPWAP_ADD_WLAN_MACMODE_SPLIT) return 0; station = wifi_station_get(wlan, frame->da); if (!station) return 0; 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; } return 1; } /* */ 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; uint16_t statuscode; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)); if (ielength < 0) return 0; station = wifi_station_get(wlan, frame->da); if (!station) return 0; switch (wlan->macmode) { case CAPWAP_ADD_WLAN_MACMODE_LOCAL: if (frame->associationresponse.statuscode != IEEE80211_STATUS_SUCCESS) { log_printf(LOG_INFO, "AC request deauthentication of station: " MACSTR, MAC2STR(station->address)); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); } return 0; case CAPWAP_ADD_WLAN_MACMODE_SPLIT: 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)); } return 1; default: break; } return 0; } /* */ 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; /* Information Elements packet length */ ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationresponse)); if (ielength < 0) return 0; switch (wlan->macmode) { case CAPWAP_ADD_WLAN_MACMODE_SPLIT: station = wifi_station_get(wlan, frame->da); if (station) { /* TODO */ } } return 0; } /* */ 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; 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_schedule_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) { switch (framecontrol_subtype) { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: return wifi_wlan_receive_ac_mgmt_authentication(wlan, frame, length); case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: return wifi_wlan_receive_ac_mgmt_association_response(wlan, frame, length); case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: return wifi_wlan_receive_ac_mgmt_reassociation_response(wlan, frame, length); case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: return wifi_wlan_receive_ac_mgmt_disassociation(wlan, frame, length); case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: return wifi_wlan_receive_ac_mgmt_deauthentication(wlan, frame, length); } return 0; } /* */ int wifi_driver_init() { int i; /* 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.devices = capwap_list_create(); g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE); g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash; g_wifiglobal.stations->item_getkey = wifi_hash_station_getkey; g_wifiglobal.stations->item_cmp = wifi_hash_station_cmp; g_wifiglobal.stations->item_free = 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); } /* */ 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_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); } /* */ 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) continue; 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)) { log_printf(LOG_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) != 0) continue; 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 (device_init(&wifi_driver[i], device)) { capwap_itemlist_free(itemdevice); return NULL; } /* 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); /* Retrieve device capability */ device_getcapability(device, device->capability); /* Appent to device list */ capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice); 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_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) continue; 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_setfrequency(device); } /* */ return result; } int wifi_device_settxqueue(struct wifi_device *device, struct capwap_80211_wtpqos_element *qos) { int i, txop; for (i = 0; i < CAPWAP_UPDATE_STATION_QOS_SUBELEMENTS; i++) { switch (i) { case 0: /* Best Effort */ txop = 0; break; case 1: /* Background */ txop = 0; break; case 2: /* Video */ txop = 94; break; case 3: /* Voice */ txop = 47; break; default: return -1; } if (device_settxqueue(device, i, qos->qos[i].aifs, qos->qos[i].cwmin, qos->qos[i].cwmax, txop) < 0) return -1; } return 0; } /* */ 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)) { log_printf(LOG_DEBUG, "update rates: supported rates failed, (%d .. %d)", buildrate.supportedratescount, IEEE80211_SUPPORTEDRATE_MAX_COUNT); return -1; } else if (!buildrate.basicratescount || (buildrate.basicratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { log_printf(LOG_DEBUG, "update rates: basic rates failed: %d", buildrate.basicratescount); 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_updatebeacons(device); return 0; } /* */ static 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; } /* */ 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)) { log_printf(LOG_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 = wlan_create(device, wlan); if (!wlan->handle) { log_printf(LOG_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)) { log_printf(LOG_WARNING, "Unable to get macaddress: %s", ifname); wifi_wlan_destroy(wlan); return NULL; } return wlan; } /* Build 802.11 Information Elements from CAPWAP Message Elements */ static void build_80211_ie(uint8_t radioid, uint8_t wlanid, uint8_t type, struct capwap_array *ie, uint8_t **ptr, int *len) { uint8_t buffer[IEEE80211_MTU]; ssize_t space = sizeof(buffer); uint8_t *pos = buffer; int i; ASSERT(ptr); ASSERT(len); log_printf(LOG_DEBUG, "WIFI 802.11: IE: %d:%d %02x, %p", radioid, wlanid, type, ie); *len = 0; *ptr = NULL; if (!ie) return; for (i = 0; i < ie->count; i++) { struct capwap_80211_ie_element *e = *(struct capwap_80211_ie_element **)capwap_array_get_item_pointer(ie, i); log_printf(LOG_DEBUG, "WIFI 802.11: IE: %d:%d %02x (%p)", radioid, wlanid, e->flags, &e->flags); if (e->radioid != radioid || e->wlanid != wlanid || !(e->flags & type)) continue; /* not enough space left */ if (e->ielength > space) continue; memcpy(pos, e->ie, e->ielength); pos += e->ielength; space -= e->ielength; } *len = pos - buffer; if (*len > 0) { *ptr = malloc(*len); if (*ptr) memcpy(*ptr, buffer, *len); } } /* Scan AC provided IEs for HT Capabilities and HT Operation */ static int ht_opmode_from_ie(uint8_t radioid, uint8_t wlanid, struct capwap_array *ie) { int i; if (!ie) return -1; for (i = 0; i < ie->count; i++) { struct ieee80211_ht_operation *ht_oper; struct capwap_80211_ie_element *e = *(struct capwap_80211_ie_element **)capwap_array_get_item_pointer(ie, i); log_printf(LOG_DEBUG, "HT Mode WIFI 802.11: IE: %d:%d %02x (%p)", radioid, wlanid, e->flags, &e->flags); if (e->radioid != radioid || e->wlanid != wlanid || !(e->flags & CAPWAP_IE_BEACONS_ASSOCIATED) || e->ielength < 2) continue; ht_oper = (struct ieee80211_ht_operation *)e->ie; log_printf(LOG_DEBUG, "HT Mode WIFI 802.11: IE: %02d (%p)", ht_oper->id, ht_oper); if (ht_oper->id == IEEE80211_IE_HT_OPERATION) return __le16_to_cpu(ht_oper->operation_mode); } log_printf(LOG_DEBUG, "WIFI 802.11: No HT Operation IE present"); return -1; } /* Scan AC provided IEs for RSNE settings */ static struct ieee80211_ie *rsn_from_ie(uint8_t radioid, uint8_t wlanid, struct capwap_array *ie) { int i; if (!ie) return NULL; for (i = 0; i < ie->count; i++) { struct ieee80211_ie *rsn; struct capwap_80211_ie_element *e = *(struct capwap_80211_ie_element **)capwap_array_get_item_pointer(ie, i); log_printf(LOG_DEBUG, "RSN WIFI 802.11: IE: %d:%d %02x (%p)", radioid, wlanid, e->flags, &e->flags); if (e->radioid != radioid || e->wlanid != wlanid || e->ielength < 2) continue; rsn = (struct ieee80211_ie *)e->ie; log_printf(LOG_DEBUG, "RSN WIFI 802.11: IE: %02d (%p)", rsn->id, rsn); if (rsn->id == IEEE80211_IE_RSN_INFORMATION) return rsn; } log_printf(LOG_DEBUG, "WIFI 802.11: No RSN IE present"); return NULL; } #define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff" static int update_keys(struct wifi_wlan* wlan, struct capwap_array *keys) { int i, result = 0; log_printf(LOG_DEBUG, "Wifi Update Keys: %p", keys); if (!keys) return 0; log_printf(LOG_DEBUG, "Wifi Update Keys: #%ld", keys->count); for (i = 0; i < keys->count; i++) { struct capwap_vendor_travelping_80211_update_key_element *key = *(struct capwap_vendor_travelping_80211_update_key_element **) capwap_array_get_item_pointer(keys, i); log_printf(LOG_DEBUG, "Wifi Update Keys: Update: Status: %d, CipherSuite: %08x, Index: %d, Len: %d", key->keystatus, key->ciphersuite, key->keyindex, key->keylength); switch (key->keystatus) { case 3: result = wlan_set_key(wlan, key->ciphersuite, broadcast_ether_addr, key->keyindex, 1, NULL, 0, key->keylength ? key->key : NULL, key->keylength); log_printf(LOG_INFO, "Update KEY on interface: %s, SSID: '%s', result: %d", wlan->virtname, wlan->ssid, result); break; default: break; } } return result; } /* */ 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; wlan->ht_opmode = ht_opmode_from_ie(wlan->radioid, wlan->wlanid, params->ie); log_printf(LOG_DEBUG, "WIFI 802.11: HT OpMode: %04x", wlan->ht_opmode); wlan->rsne = rsn_from_ie(wlan->radioid, wlan->wlanid, params->ie); wlan->keyindex = params->keyindex; wlan->keylength = params->keylength; if (params->key && params->keylength) wlan->key = capwap_clone(params->key, params->keylength); build_80211_ie(wlan->radioid, wlan->wlanid, CAPWAP_IE_BEACONS_ASSOCIATED, params->ie, &wlan->beacon_ies, &wlan->beacon_ies_len); build_80211_ie(wlan->radioid, wlan->wlanid, CAPWAP_IE_PROBE_RESPONSE_ASSOCIATED, params->ie, &wlan->response_ies, &wlan->response_ies_len); /* Start AP */ result = wlan_startap(wlan); if (result) { wifi_wlan_stopap(wlan); return result; } update_keys(wlan, params->updatekeys); wlan->device->wlanactive++; log_printf(LOG_INFO, "Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid); return result; } /* */ int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* params) { int result = 0; ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); ASSERT(params != NULL); /* Check device */ if (!(wlan->flags & WIFI_WLAN_RUNNING)) return -1; /* Save configuration */ #if 0 /* TODO: handle changes in WLAN setting */ wlan->capability = params->capability; wlan->ht_opmode = ht_opmode_from_ie(wlan->radioid, wlan->wlanid, params->ie); log_printf(LOG_DEBUG, "WIFI 802.11: HT OpMode: %04x", wlan->ht_opmode); wlan->rsne = rsn_from_ie(wlan->radioid, wlan->wlanid, params->ie); /* TODO: handle changes in WLAN setting */ build_80211_ie(wlan->radioid, wlan->wlanid, CAPWAP_IE_BEACONS_ASSOCIATED, params->ie, &wlan->beacon_ies, &wlan->beacon_ies_len); build_80211_ie(wlan->radioid, wlan->wlanid, CAPWAP_IE_PROBE_RESPONSE_ASSOCIATED, params->ie, &wlan->response_ies, &wlan->response_ies_len); #endif switch (params->keystatus) { case 3: wlan->keyindex = params->keyindex; wlan->keylength = params->keylength; if (wlan->key) { capwap_free(wlan->key); wlan->key = NULL; } if (params->key && params->keylength) wlan->key = capwap_clone(params->key, params->keylength); result = wlan_set_key(wlan, wlan->group_cipher_suite, broadcast_ether_addr, wlan->keyindex, 1, NULL, 0, wlan->key, wlan->keylength); log_printf(LOG_INFO, "Update GTK on interface: %s, SSID: '%s', result: %d", wlan->virtname, wlan->ssid, result); break; default: break; } if (!result) update_keys(wlan, params->updatekeys); return result; } /* */ void wifi_wlan_stopap(struct wifi_wlan* wlan) { ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); /* Stop AP */ wlan_stopap(wlan); free(wlan->beacon_ies); wlan->beacon_ies = NULL; free(wlan->response_ies); wlan->response_ies = NULL; /* */ 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 result; } /* */ 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_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_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) log_printf(LOG_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; if (params->key) station->key = (struct capwap_80211_stationkey_element *) capwap_element_80211_stationkey_ops.clone(params->key); station->pairwise_cipher = params->pairwise; if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { result = wifi_station_set_key(wlan, station); if (result) { wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); return result; } return 0; } if (params->ht_cap) { memcpy(&station->ht_cap, params->ht_cap, sizeof(station->ht_cap)); station->flags |= WIFI_STATION_FLAGS_HT_CAP; } station->max_inactivity = params->max_inactivity; /* 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 = station_authorize(wlan, station); if (!result) result = wifi_station_set_key(wlan, station); if (result) { wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID); return result; } /* let the timer expire, but set the action to SEND NULLFUNC */ station->timeout_action = WIFI_STATION_TIMEOUT_ACTION_SEND_NULLFUNC; return 0; } /* */ int wifi_station_set_key(struct wifi_wlan *wlan, struct wifi_station* station) { ASSERT(wlan != NULL); ASSERT(wlan->device != NULL); ASSERT(station != NULL); if (station->pairwise_cipher) return wlan_set_key(wlan, station->pairwise_cipher, station->address, 0, 1, NULL, 0, station->key->key, station->key->keylength); return wlan_set_key(wlan, station->pairwise_cipher, station->address, 0, 1, NULL, 0, NULL, 0); } /* */ 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); } /* */ 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; }