diff --git a/build/ac/Makefile.am b/build/ac/Makefile.am index 7bbabab..7eca53a 100755 --- a/build/ac/Makefile.am +++ b/build/ac/Makefile.am @@ -82,7 +82,8 @@ ac_SOURCES = \ $(top_srcdir)/src/ac/ac_dfa_run.c \ $(top_srcdir)/src/ac/ac_dfa_reset.c \ $(top_srcdir)/src/ac/ac_dfa_teardown.c \ - $(top_srcdir)/src/ac/ac_soap.c + $(top_srcdir)/src/ac/ac_soap.c \ + $(top_srcdir)/src/binding/ieee80211/ieee80211.c ac_LDADD = \ $(CONFIG_LIBS) \ diff --git a/build/wtp/Makefile.am b/build/wtp/Makefile.am index 768856a..27443a6 100755 --- a/build/wtp/Makefile.am +++ b/build/wtp/Makefile.am @@ -54,6 +54,7 @@ wtp_SOURCES = \ $(top_srcdir)/src/wtp/wtp_dfa_reset.c \ $(top_srcdir)/src/wtp/wtp_dfa_imagedata.c \ $(top_srcdir)/src/wtp/wtp_radio.c \ + $(top_srcdir)/src/binding/ieee80211/ieee80211.c \ $(top_srcdir)/src/binding/ieee80211/wifi_drivers.c wtp_LDADD = \ diff --git a/src/ac/ac_backend.c b/src/ac/ac_backend.c index a1473a6..d5b1888 100644 --- a/src/ac/ac_backend.c +++ b/src/ac/ac_backend.c @@ -275,7 +275,7 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj addwlan->authmode = (uint8_t)json_object_get_int(jsonauthtype); addwlan->macmode = (uint8_t)json_object_get_int(jsonmacmode); addwlan->tunnelmode = (uint8_t)json_object_get_int(jsontunnelmode); - addwlan->suppressssid = (uint8_t)(json_object_get_boolean(jsonhidessid) ? 0 : 1); + addwlan->suppressssid = (uint8_t)(json_object_get_boolean(jsonhidessid) ? 1 : 0); strcpy(addwlan->ssid, ssid); /* Notify Request to Complete Event */ diff --git a/src/binding/ieee80211/ieee80211.c b/src/binding/ieee80211/ieee80211.c new file mode 100644 index 0000000..16021bc --- /dev/null +++ b/src/binding/ieee80211/ieee80211.c @@ -0,0 +1,267 @@ +#include "capwap.h" +#include "ieee80211.h" + +/* */ +static int ieee80211_ie_set_ssid(char* buffer, const char* ssid, int hidessid) { + struct ieee80211_ie_ssid* iessid = (struct ieee80211_ie_ssid*)buffer; + + ASSERT(buffer != NULL); + ASSERT(ssid != NULL); + + iessid->id = IEEE80211_IE_SSID; + if (hidessid) { + iessid->len = 0; + } else { + iessid->len = strlen(ssid); + if (iessid->len > IEEE80211_IE_SSID_MAX_LENGTH) { + return -1; + } + + strncpy((char*)iessid->ssid, ssid, iessid->len); + } + + return sizeof(struct ieee80211_ie_ssid) + iessid->len; +} + +/* */ +static int ieee80211_ie_set_supportedrates(char* buffer, uint8_t* supportedrates, int supportedratescount) { + int i; + int count; + struct ieee80211_ie_supported_rates* iesupportedrates = (struct ieee80211_ie_supported_rates*)buffer; + + ASSERT(buffer != NULL); + ASSERT(supportedrates != NULL); + ASSERT(supportedratescount > 0); + + /* IE accept max only 8 rate */ + count = supportedratescount; + if (count > 8) { + count = 8; + } + + /* */ + iesupportedrates->id = IEEE80211_IE_SUPPORTED_RATES; + iesupportedrates->len = count; + + for (i = 0; i < count; i++) { + iesupportedrates->rates[i] = supportedrates[i]; + } + + return sizeof(struct ieee80211_ie_supported_rates) + iesupportedrates->len; +} + +/* */ +static int ieee80211_ie_set_extendedsupportedrates(char* buffer, uint8_t* supportedrates, int supportedratescount) { + int i, j; + struct ieee80211_ie_extended_supported_rates* ieextendedsupportedrates = (struct ieee80211_ie_extended_supported_rates*)buffer; + + ASSERT(buffer != NULL); + ASSERT(supportedrates != NULL); + + /* IE accept only > 8 rate */ + if (supportedratescount <= IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH) { + return 0; + } + + /* */ + ieextendedsupportedrates->id = IEEE80211_IE_EXTENDED_SUPPORTED_RATES; + ieextendedsupportedrates->len = supportedratescount - IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH; + + for (i = IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH, j = 0; i < supportedratescount; i++, j++) { + ieextendedsupportedrates->rates[j] = supportedrates[i]; + } + + return sizeof(struct ieee80211_ie_extended_supported_rates) + ieextendedsupportedrates->len; +} + +/* */ +static int ieee80211_ie_set_dsss(char* buffer, uint8_t channel) { + struct ieee80211_ie_dsss* iedsss = (struct ieee80211_ie_dsss*)buffer; + + ASSERT(buffer != NULL); + + iedsss->id = IEEE80211_IE_DSSS; + iedsss->len = 1; + iedsss->channel = channel; + + return sizeof(struct ieee80211_ie_dsss); +} + +/* */ +static int ieee80211_ie_set_erp(char* buffer, uint32_t mode) { + struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; + + ASSERT(buffer != NULL); + + if (!(mode & IEEE80211_RADIO_TYPE_80211G)) { + return 0; + } + + ieerp->id = IEEE80211_IE_ERP; + ieerp->len = 1; + ieerp->params = 0; /* TODO */ + + return sizeof(struct ieee80211_ie_erp); +} + +/* */ +int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_params* params) { + int result; + char* pos; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + ASSERT(length == IEEE80211_MTU); + + /* */ + memset(buffer, 0x00, length); + header = (struct ieee80211_header_mgmt*)buffer; + params->headbeacon = buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON); + memset(header->da, 0xff, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->beacon.beaconinterval = __cpu_to_le16(params->beaconperiod); + header->beacon.capability = __cpu_to_le16(params->capability); + + /* Header frame size */ + params->headbeaconlength = (int)((uint8_t*)&header->beacon.ie[0] - (uint8_t*)header); + pos = buffer + params->headbeaconlength; + + /* Information Element: SSID */ + result = ieee80211_ie_set_ssid(pos, params->ssid, (params->ssid_hidden ? 1 : 0)); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Information Element: Supported Rates */ + result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Information Element: DSSS */ + result = ieee80211_ie_set_dsss(pos, params->channel); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Separate Information Elements into two block between IE TIM */ + params->tailbeacon = pos; + params->tailbeaconlength = 0; + + /* Information Element: Country */ + /* TODO */ + + /* Information Element: ERP */ + result = ieee80211_ie_set_erp(pos, params->erpmode); + if (result < 0) { + return -1; + } + + pos += result; + params->tailbeaconlength += result; + + /* Information Element: Extended Supported Rates */ + result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + params->tailbeaconlength += result; + + return (params->headbeaconlength + params->tailbeaconlength); +} + +/* */ +int ieee80211_create_probe_response(char* buffer, int length, const struct ieee80211_header_mgmt* proberequestheader, struct ieee80211_probe_response_params* params) { + int result; + char* pos; + int responselength; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + ASSERT(length == IEEE80211_MTU); + + /* */ + memset(buffer, 0x00, length); + header = (struct ieee80211_header_mgmt*)buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESP); + if (proberequestheader) { + memcpy(header->da, proberequestheader->sa, ETH_ALEN); + } else { + memset(header->da, 0x00, ETH_ALEN); + } + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->proberesponse.beaconinterval = __cpu_to_le16(params->beaconperiod); + header->proberesponse.capability = __cpu_to_le16(params->capability); + + /* Header frame size */ + responselength = (int)((uint8_t*)&header->proberesponse.ie[0] - (uint8_t*)header); + pos = buffer + responselength; + + /* Information Element: SSID */ + result = ieee80211_ie_set_ssid(pos, params->ssid, 0); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Supported Rates */ + result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: DSSS */ + result = ieee80211_ie_set_dsss(pos, params->channel); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Country */ + /* TODO */ + + /* Information Element: ERP */ + result = ieee80211_ie_set_erp(pos, params->erpmode); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Extended Supported Rates */ + result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + return responselength; +} \ No newline at end of file diff --git a/src/binding/ieee80211/ieee80211.h b/src/binding/ieee80211/ieee80211.h index 825f536..bc25547 100644 --- a/src/binding/ieee80211/ieee80211.h +++ b/src/binding/ieee80211/ieee80211.h @@ -10,10 +10,17 @@ #endif /* Global values */ -#define IEEE80211_MTU 2304 +#define IEEE80211_MTU 2304 +/* Radio type with value same of IEEE802.11 Radio Information Message Element */ +#define IEEE80211_RADIO_TYPE_80211B 0x00000001 +#define IEEE80211_RADIO_TYPE_80211A 0x00000002 +#define IEEE80211_RADIO_TYPE_80211G 0x00000004 +#define IEEE80211_RADIO_TYPE_80211N 0x00000008 + +/* */ #define IS_IEEE80211_FREQ_BG(x) (((x >= 2412) && (x <= 2484)) ? 1 : 0) -#define IS_IEEE80211_FREQ_A(x) (((x >= 5035) && (x <= 5825)) ? 1 : 0) +#define IS_IEEE80211_FREQ_A(x) ((((x >= 4915) && (x <= 4980)) || ((x >= 5035) && (x <= 5825))) ? 1 : 0) /* Rate into multiple of 500Kbps */ #define IEEE80211_RATE_1M 2 @@ -35,6 +42,11 @@ #define IS_IEEE80211_RATE_A(x) (((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_9M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_18M) || (x == IEEE80211_RATE_24M) || (x == IEEE80211_RATE_36M) || (x == IEEE80211_RATE_48M) || (x == IEEE80211_RATE_54M)) ? 1 : 0) #define IS_IEEE80211_RATE_N(x) ((x == IEEE80211_RATE_80211N) ? 1 : 0) +#define IEEE80211_BASICRATE 128 +#define IS_IEEE80211_BASICRATE_B(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M)) +#define IS_IEEE80211_BASICRATE_G(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M) || (x == IEEE80211_RATE_5_5M) || (x == IEEE80211_RATE_11M)) +#define IS_IEEE80211_BASICRATE_A(x) ((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_24M)) + /* Frame control type */ #define IEEE80211_FRAMECONTROL_TYPE_MGMT 0 #define IEEE80211_FRAMECONTROL_TYPE_CTRL 1 @@ -85,7 +97,9 @@ #define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSCFACK_CFPOLL 15 /* */ -#define IEEE80211_FRAME_CONTROL(type, stype) __cpu_to_le16((type << 2) | (stype << 4)) +#define IEEE80211_FRAME_CONTROL(type, stype) __cpu_to_le16((type << 2) | (stype << 4)) +#define IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol) (((framecontrol) & 0x000c) >> 2) +#define IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol) (((framecontrol) & 0x00f0) >> 4) /* 802.11 Packet - IEEE802.11 is a little-endian protocol */ struct ieee80211_header { @@ -106,9 +120,25 @@ struct ieee80211_header_mgmt { uint8_t bssid[ETH_ALEN]; __le16 sequencecontrol; - uint8_t timestamp[8]; - __le16 beaconinterval; - __le16 capability; + union { + struct { + uint8_t timestamp[8]; + __le16 beaconinterval; + __le16 capability; + uint8_t ie[0]; + } STRUCT_PACKED beacon; + + struct { + uint8_t ie[0]; + } STRUCT_PACKED proberequest; + + struct { + uint8_t timestamp[8]; + __le16 beaconinterval; + __le16 capability; + uint8_t ie[0]; + } STRUCT_PACKED proberesponse; + }; } STRUCT_PACKED; /* 802.11 Generic information element */ @@ -190,6 +220,8 @@ struct ieee80211_ie_extended_supported_rates { #define EDCA_PARAMETER_RECORD_AC_VO_FIELD 3 struct ieee80211_ie_edca_parameter_set { + uint8_t id; + uint8_t len; /* TODO */ } STRUCT_PACKED; @@ -198,15 +230,98 @@ struct ieee80211_ie_edca_parameter_set { #define IEEE80211_IE_QOS_CAPABILITY_LENGTH 1 struct ieee80211_ie_qos_capability { + uint8_t id; + uint8_t len; /* TODO */ -}; +} STRUCT_PACKED; /* 802.11 Power Constraint information element */ #define IEEE80211_IE_POWER_CONSTRAINT 52 #define IEEE80211_IE_POWER_CONSTRAINT_LENGTH 1 struct ieee80211_ie_power_constraint { + uint8_t id; + uint8_t len; /* TODO */ } STRUCT_PACKED; +/* 802.11 SSID List */ +#define IEEE80211_IE_SSID_LIST 84 + +struct ieee80211_ie_ssid_list { + uint8_t id; + uint8_t len; + uint8_t lists[0]; +} STRUCT_PACKED; + +/* 802.11 All information elements */ +struct ieee80211_ie_items { + struct ieee80211_ie_ssid* ssid; + struct ieee80211_ie_supported_rates* supported_rates; + struct ieee80211_ie_dsss* dsss; + struct ieee80211_ie_country* country; + struct ieee80211_ie_erp* erp; + struct ieee80211_ie_extended_supported_rates* extended_supported_rates; + struct ieee80211_ie_edca_parameter_set* edca_parameter_set; + struct ieee80211_ie_qos_capability* qos_capability; + struct ieee80211_ie_power_constraint* power_constraint; + struct ieee80211_ie_ssid_list* ssid_list; +}; + +/* IEEE 802.11 functions */ +#define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 + +/* Management Beacon */ +struct ieee80211_beacon_params { + /* Beacon packet */ + char* headbeacon; + int headbeaconlength; + char* tailbeacon; + int tailbeaconlength; + + /* Header information */ + uint8_t bssid[ETH_ALEN]; + uint16_t beaconperiod; + uint16_t capability; + + /* SSID */ + const char* ssid; + int ssid_hidden; + + /* Supported Rates */ + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* DSSS */ + uint8_t channel; + + /* ERP */ + uint32_t erpmode; +}; + +int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_params* params); + +/* Management Probe Response */ +struct ieee80211_probe_response_params { + /* Header information */ + uint8_t bssid[ETH_ALEN]; + uint16_t beaconperiod; + uint16_t capability; + + /* SSID */ + const char* ssid; + + /* Supported Rates */ + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* DSSS */ + uint8_t channel; + + /* ERP */ + uint32_t erpmode; +}; + +int ieee80211_create_probe_response(char* buffer, int length, const struct ieee80211_header_mgmt* proberequestheader, struct ieee80211_probe_response_params* params); + #endif /* __CAPWAP_IEEE802_11_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_drivers.c b/src/binding/ieee80211/wifi_drivers.c index 5c389ee..e665f04 100644 --- a/src/binding/ieee80211/wifi_drivers.c +++ b/src/binding/ieee80211/wifi_drivers.c @@ -3,7 +3,6 @@ #include "capwap_element.h" #include "wtp_radio.h" #include "wifi_drivers.h" -#include "ieee80211.h" /* Declare enable wifi driver */ #ifdef ENABLE_WIFI_DRIVERS_NL80211 @@ -20,36 +19,6 @@ static struct wifi_driver_instance wifi_driver[] = { /* Radio instance */ static struct capwap_array* g_wifidevice = NULL; -/* */ -static void wifi_device_freecapability(struct wifi_capability* capability) { - int i; - - ASSERT(capability != NULL); - - /* Free memory */ - if (capability->bands) { - 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->freq) { - capwap_array_free(bandcap->freq); - } - - if (bandcap->rate) { - capwap_array_free(bandcap->rate); - } - } - - capwap_array_free(capability->bands); - } - - if (capability->ciphers) { - capwap_array_free(capability->ciphers); - } - - capwap_free(capability); -} - /* */ int wifi_driver_init(void) { int i; @@ -93,10 +62,6 @@ void wifi_driver_free(void) { capwap_array_free(device->wlan); } - if (device->capability) { - wifi_device_freecapability(device->capability); - } - if (device->handle && device->instance->ops->device_deinit) { device->instance->ops->device_deinit(device->handle); } @@ -291,7 +256,9 @@ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid /* */ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* radio) { int i, j, w; + int radiotype; uint32_t mode = 0; + const struct wifi_capability* capability; ASSERT(device != NULL); ASSERT(radio != NULL); @@ -299,11 +266,16 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad /* Free old supported rates */ device->supportedratescount = 0; - /* Retrieve cached capability */ - if (!device->capability) { - if (!wifi_device_getcapability(radio->radioid)) { - return; - } + /* Retrieve capability */ + capability = wifi_device_getcapability(radio->radioid); + if (!capability) { + return; + } + + /* Get radio type for basic rate */ + radiotype = wifi_frequency_to_radiotype(device->currentfreq.frequency); + if (radiotype < 0) { + return; } /* Check type of rate mode */ @@ -334,20 +306,18 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } /* Filter band */ - 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); + 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->currentfreq.band) { - if (bandcap->rate->count) { - for (j = 0; j < bandcap->rate->count; j++) { - struct wifi_rate_capability* rate = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); + for (j = 0; j < bandcap->rate->count; j++) { + struct wifi_rate_capability* rate = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); - /* Validate rate */ - for (w = 0; w < radio->rateset.ratesetcount; w++) { - if (radio->rateset.rateset[w] == rate->bitrate) { - device->supportedrates[device->supportedratescount++] = rate->bitrate; - break; - } + /* Validate rate */ + for (w = 0; w < radio->rateset.ratesetcount; w++) { + if (radio->rateset.rateset[w] == rate->bitrate) { + device->supportedrates[device->supportedratescount++] = rate->bitrate; + break; } } } @@ -356,6 +326,23 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } } + /* Apply basic rate */ + for (i = 0; i < device->supportedratescount; i++) { + if (radiotype == CAPWAP_RADIO_TYPE_80211A) { + if (IS_IEEE80211_BASICRATE_A(device->supportedrates[i])) { + device->supportedrates[i] |= IEEE80211_BASICRATE; + } + } else if (radiotype == CAPWAP_RADIO_TYPE_80211B) { + if (IS_IEEE80211_BASICRATE_B(device->supportedrates[i])) { + device->supportedrates[i] |= IEEE80211_BASICRATE; + } + } else if (radiotype == CAPWAP_RADIO_TYPE_80211G) { + if (IS_IEEE80211_BASICRATE_G(device->supportedrates[i])) { + device->supportedrates[i] |= IEEE80211_BASICRATE; + } + } + } + /* Add implicit 802.11n rate with only 802.11a/g rate */ if (!(mode & CAPWAP_RADIO_TYPE_80211N) && (device->currentfreq.mode & CAPWAP_RADIO_TYPE_80211N)) { device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_80211N; @@ -363,216 +350,59 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } /* */ -static int wifi_ie_ssid(char* buffer, const char* ssid, int hidessid) { - struct ieee80211_ie_ssid* iessid = (struct ieee80211_ie_ssid*)buffer; - - ASSERT(buffer != NULL); - ASSERT(ssid != NULL); - - iessid->id = IEEE80211_IE_SSID; - if (!hidessid) { - iessid->len = strlen(ssid); - if (iessid->len > IEEE80211_IE_SSID_MAX_LENGTH) { - return -1; - } - - strncpy((char*)iessid->ssid, ssid, iessid->len); - } - - return sizeof(struct ieee80211_ie_ssid) + iessid->len; -} - -/* */ -static int wifi_ie_supportedrates(char* buffer, struct wifi_device* device) { - int i; - int count; - struct ieee80211_ie_supported_rates* iesupportedrates = (struct ieee80211_ie_supported_rates*)buffer; - - ASSERT(buffer != NULL); - - /* IE accept max only 8 rate */ - count = device->supportedratescount; - if (count > 8) { - count = 8; - } - - /* */ - iesupportedrates->id = IEEE80211_IE_SUPPORTED_RATES; - iesupportedrates->len = count; - - for (i = 0; i < count; i++) { - iesupportedrates->rates[i] = device->supportedrates[i]; - } - - return sizeof(struct ieee80211_ie_supported_rates) + iesupportedrates->len; -} - -/* */ -static int wifi_ie_extendedsupportedrates(char* buffer, struct wifi_device* device) { - int i, j; - struct ieee80211_ie_extended_supported_rates* ieextendedsupportedrates = (struct ieee80211_ie_extended_supported_rates*)buffer; - - ASSERT(buffer != NULL); - - /* IE accept only > 8 rate */ - if (device->supportedratescount <= IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH) { - return 0; - } - - /* */ - ieextendedsupportedrates->id = IEEE80211_IE_EXTENDED_SUPPORTED_RATES; - ieextendedsupportedrates->len = device->supportedratescount - IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH; - - for (i = IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH, j = 0; i < device->supportedratescount; i++, j++) { - ieextendedsupportedrates->rates[j] = device->supportedrates[i]; - } - - return sizeof(struct ieee80211_ie_extended_supported_rates) + ieextendedsupportedrates->len; -} - -/* */ -static int wifi_ie_dsss(char* buffer, struct wifi_device* device) { - struct ieee80211_ie_dsss* iedsss; - - ASSERT(buffer != NULL); - ASSERT(device != NULL); - - iedsss = (struct ieee80211_ie_dsss*)buffer; - iedsss->id = IEEE80211_IE_SSID; - iedsss->len = 1; - iedsss->channel = device->currentfreq.channel; - - return sizeof(struct ieee80211_ie_dsss); -} - -/* */ -static int wifi_ie_erp(char* buffer, struct wifi_device* device) { - ASSERT(buffer != NULL); - ASSERT(device != NULL); - - return 0; - - /* TODO implements params ERP - struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; - - if (device->currentfreq.mode != CAPWAP_RADIO_TYPE_80211G) { - return 0; - } - - ieerp->id = IEEE80211_IE_ERP; - ieerp->len = 1; - iedsss->params = 0; - - return sizeof(struct ieee80211_ie_erp); - */ -} - -/* */ -int wifi_wlan_setupap(struct capwap_80211_addwlan_element* addwlan, struct capwap_array* ies) { - int result; +int wifi_wlan_setupap(int radioid, int wlanid) { struct wifi_wlan* wlan; - struct wtp_radio* radio; - char buffer[IEEE80211_MTU]; - struct ieee80211_header_mgmt* header; - struct wlan_setupap_params params; - ASSERT(addwlan != NULL); - - /* Get WLAN and Radio information */ - wlan = wifi_wlan_getdevice(addwlan->radioid, addwlan->wlanid); - radio = wtp_radio_get_phy(addwlan->radioid); - if (!wlan || !radio || !wlan->handle || !wlan->device) { - return -1; - } else if (!wlan->device->instance->ops->wlan_setupap) { - return -1; - } + ASSERT(radioid > 0); + ASSERT(wlanid > 0); /* */ - memset(buffer, 0, sizeof(buffer)); - header = (struct ieee80211_header_mgmt*)buffer; - - /* */ - memset(¶ms, 0, sizeof(struct wlan_setupap_params)); - params.headbeacon = buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON); - memset(header->da, 0xff, ETH_ALEN); - wlan->device->instance->ops->wlan_getmacaddress(wlan->handle, header->sa); - memcpy(header->bssid, header->sa, ETH_ALEN); - header->beaconinterval = __cpu_to_le16(radio->radioconfig.beaconperiod); - header->capability = __cpu_to_le16(addwlan->capability); - params.headbeaconlength += sizeof(struct ieee80211_header_mgmt); - - /* Information Element: SSID */ - result = wifi_ie_ssid(¶ms.headbeacon[params.headbeaconlength], (const char*)addwlan->ssid, (addwlan->suppressssid ? 1 : 0)); - if (result < 0) { + wlan = wifi_wlan_getdevice(radioid, wlanid); + if (!wlan || !wlan->device->instance->ops->wlan_setupap) { return -1; } - params.headbeaconlength += result; - - /* Information Element: Supported Rates */ - wifi_wlan_getrates(wlan->device, radio); - result = wifi_ie_supportedrates(¶ms.headbeacon[params.headbeaconlength], wlan->device); - if (result < 0) { - return -1; - } - - params.headbeaconlength += result; - - /* Information Element: DSSS */ - result = wifi_ie_dsss(¶ms.headbeacon[params.headbeaconlength], wlan->device); - if (result < 0) { - return -1; - } - - params.headbeaconlength += result; - - /* Separate Information Elements into two block between IE TIM */ - params.tailbeacon = ¶ms.headbeacon[params.headbeaconlength]; - - /* Information Element: Country */ - /* TODO */ - - /* Information Element: ERP */ - result = wifi_ie_erp(¶ms.tailbeacon[params.tailbeaconlength], wlan->device); - if (result < 0) { - return -1; - } - - params.tailbeaconlength += result; - - /* Information Element: Extended Supported Rates */ - result = wifi_ie_extendedsupportedrates(¶ms.tailbeacon[params.tailbeaconlength], wlan->device); - if (result < 0) { - return -1; - } - - params.tailbeaconlength += result; - - /* Set configuration params */ - strcpy(params.ssid, (const char*)addwlan->ssid); - params.suppressssid = addwlan->suppressssid; - params.beaconinterval = radio->radioconfig.beaconperiod; - params.dtimperiod = radio->radioconfig.dtimperiod; - params.authenticationtype = addwlan->authmode; - - /* Configuration complete */ - return wlan->device->instance->ops->wlan_setupap(wlan->handle, ¶ms); + return wlan->device->instance->ops->wlan_setupap(wlan->handle); } /* */ int wifi_wlan_startap(int radioid, int wlanid) { struct wifi_wlan* wlan; + struct wtp_radio* radio; + struct wtp_radio_wlan* radiowlan; + struct wlan_startap_params wlan_params; + + ASSERT(radioid > 0); + ASSERT(wlanid > 0); /* */ wlan = wifi_wlan_getdevice(radioid, wlanid); - if (!wlan->device->instance->ops->wlan_startap) { + radio = wtp_radio_get_phy(radioid); + if (!wlan || !radio || !wlan->device->instance->ops->wlan_startap) { return -1; } - return wlan->device->instance->ops->wlan_startap(wlan->handle); + /* */ + radiowlan = wtp_radio_get_wlan(radio, wlanid); + if (!radiowlan) { + return -1; + } + + /* Retrieve supported rates */ + wifi_wlan_getrates(wlan->device, radiowlan->radio); + + /* Start AP */ + memset(&wlan_params, 0, sizeof(struct wlan_startap_params)); + wlan_params.ssid = radiowlan->ssid; + wlan_params.ssid_hidden = radiowlan->ssid_hidden; + wlan_params.beaconperiod = radio->radioconfig.beaconperiod; + wlan_params.capability = radiowlan->capability; + wlan_params.dtimperiod = radio->radioconfig.dtimperiod; + memcpy(wlan_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); + wlan_params.supportedratescount = wlan->device->supportedratescount; + wlan_params.authenticationtype = radiowlan->authmode; + + return wlan->device->instance->ops->wlan_startap(wlan->handle, &wlan_params); } /* */ @@ -619,7 +449,7 @@ void wifi_wlan_destroy(int radioid, int wlanid) { } /* */ -struct wifi_capability* wifi_device_getcapability(int radioid) { +const struct wifi_capability* wifi_device_getcapability(int radioid) { struct wifi_device* device; ASSERT(radioid > 0); @@ -630,29 +460,18 @@ struct wifi_capability* wifi_device_getcapability(int radioid) { /* Retrieve cached capability */ device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (!device->capability && device->handle && device->instance->ops->device_getcapability) { - /* Get capability from device */ - 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); - - /* */ - if (device->instance->ops->device_getcapability(device->handle, device->capability)) { - wifi_device_freecapability(device->capability); - device->capability = NULL; - } + if (!device->handle || !device->instance->ops->device_getcapability) { + return NULL; } - return device->capability; + return device->instance->ops->device_getcapability(device->handle); } /* */ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel) { int i, j; int result = -1; - struct wifi_capability* capability; + const struct wifi_capability* capability; uint32_t frequency = 0; ASSERT(radioid > 0); @@ -768,14 +587,148 @@ int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr) { } /* */ -unsigned long wifi_frequency_to_channel(unsigned long freq) { +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; +} + +/* */ +unsigned long wifi_frequency_to_channel(uint32_t freq) { if ((freq >= 2412) && (freq <= 2472)) { return (freq - 2407) / 5; } else if (freq == 2484) { return 14; + } else if ((freq >= 4915) && (freq <= 4980)) { + return (freq - 4000) / 5; } else if ((freq >= 5035) && (freq <= 5825)) { - return freq / 5 - 1000; + return (freq - 5000) / 5; } return 0; } + +/* */ +int wifi_is_broadcast_addr(const uint8_t* addr) { + return (((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)) ? 1 : 0); +} + +/* */ +int wifi_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist) { + int ssidlength; + + ASSERT(ssid != NULL); + ASSERT(iessid != NULL); + + /* Check SSID */ + ssidlength = strlen((char*)ssid); + if ((ssidlength == iessid->len) && !memcmp(ssid, iessid->ssid, ssidlength)) { + return WIFI_VALID_SSID; + } + + /* Check SSID list */ + if (isssidlist) { + int length = isssidlist->len; + uint8_t* pos = isssidlist->lists; + + while (length >= sizeof(struct ieee80211_ie)) { + struct ieee80211_ie_ssid* ssiditem = (struct ieee80211_ie_ssid*)pos; + + /* Check buffer */ + length -= sizeof(struct ieee80211_ie); + if ((ssiditem->id != IEEE80211_IE_SSID) || !ssiditem->len || (length < ssiditem->len)) { + break; + } else if ((ssidlength == ssiditem->len) && !memcmp(ssid, ssiditem->ssid, ssidlength)) { + return WIFI_VALID_SSID; + } + + /* Next */ + length -= ssiditem->len; + pos += sizeof(struct ieee80211_ie) + ssiditem->len; + } + } + + return (!iessid->len ? WIFI_WILDCARD_SSID : WIFI_WRONG_SSID); +} + +/* */ +int wifi_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length) { + ASSERT(items != NULL); + ASSERT(data != NULL); + + /* */ + memset(items, 0, sizeof(struct ieee80211_ie_items)); + + /* Parsing */ + while (length >= 2) { + uint8_t ie_id = data[0]; + uint8_t ie_len = data[1]; + + /* Parsing Information Element */ + switch (ie_id) { + case IEEE80211_IE_SSID: { + items->ssid = (struct ieee80211_ie_ssid*)data; + break; + } + + case IEEE80211_IE_SUPPORTED_RATES: { + items->supported_rates = (struct ieee80211_ie_supported_rates*)data; + break; + } + + case IEEE80211_IE_DSSS: { + items->dsss = (struct ieee80211_ie_dsss*)data; + break; + } + + case IEEE80211_IE_COUNTRY: { + items->country = (struct ieee80211_ie_country*)data; + break; + } + + case IEEE80211_IE_ERP: { + items->erp = (struct ieee80211_ie_erp*)data; + break; + } + + case IEEE80211_IE_EXTENDED_SUPPORTED_RATES: { + items->extended_supported_rates = (struct ieee80211_ie_extended_supported_rates*)data; + break; + } + + case IEEE80211_IE_EDCA_PARAMETER_SET: { + items->edca_parameter_set = (struct ieee80211_ie_edca_parameter_set*)data; + break; + } + + case IEEE80211_IE_QOS_CAPABILITY: { + items->qos_capability = (struct ieee80211_ie_qos_capability*)data; + break; + } + + case IEEE80211_IE_POWER_CONSTRAINT: { + items->power_constraint = (struct ieee80211_ie_power_constraint*)data; + break; + } + + case IEEE80211_IE_SSID_LIST: { + items->ssid_list = (struct ieee80211_ie_ssid_list*)data; + break; + } + } + + /* Next Information Element */ + data += sizeof(struct ieee80211_ie) + ie_len; + length -= sizeof(struct ieee80211_ie) + ie_len; + } + + return (!length ? 0 : -1); +} diff --git a/src/binding/ieee80211/wifi_drivers.h b/src/binding/ieee80211/wifi_drivers.h index 3998016..85c1f54 100644 --- a/src/binding/ieee80211/wifi_drivers.h +++ b/src/binding/ieee80211/wifi_drivers.h @@ -3,6 +3,7 @@ #include #include +#include "ieee80211.h" /* */ #define WIFI_DRIVER_NAME_SIZE 16 @@ -13,15 +14,22 @@ #define WIFI_BAND_2GHZ 1 #define WIFI_BAND_5GHZ 2 -/* */ -#define WIFI_SUPPORTEDRATE_MAX_COUNT 16 - /* */ #define WIFI_CAPABILITY_RADIOSUPPORTED 0x00000001 #define WIFI_CAPABILITY_RADIOTYPE 0x00000002 #define WIFI_CAPABILITY_BANDS 0x00000004 #define WIFI_CAPABILITY_CIPHERS 0x00000008 #define WIFI_CAPABILITY_ANTENNA_MASK 0x00000010 +#define WIFI_CAPABILITY_MAX_SCAN_SSIDS 0x00000020 +#define WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS 0x00000040 +#define WIFI_CAPABILITY_MAX_MATCH_SETS 0x00000080 +#define WIFI_CAPABILITY_MAX_ACL_MACADDRESS 0x00000100 + +/* */ +#define WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK 0x00000001 +#define WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT 0x00000002 +#define WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD 0x00000004 +#define WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME 0x00000008 /* */ #define WIFI_CAPABILITY_AP_SUPPORTED 0x00000001 @@ -71,21 +79,34 @@ struct wlan_init_params { }; /* */ -struct wlan_setupap_params { - char* headbeacon; - int headbeaconlength; - char* tailbeacon; - int tailbeaconlength; +struct wlan_startap_params { + const char* ssid; + uint8_t ssid_hidden; - char ssid[WIFI_SSID_MAX_LENGTH + 1]; - uint8_t suppressssid; - - uint16_t beaconinterval; + uint16_t beaconperiod; + uint16_t capability; uint8_t dtimperiod; + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + uint8_t authenticationtype; }; +/* */ +struct wlan_send_frame_params { + char* packet; + int length; + + uint32_t frequency; + uint32_t duration; + int offchannel_tx_ok; + int no_cck_rate; + int no_wait_ack; + + uint64_t cookie; +}; + /* Interface capability */ struct wifi_freq_capability { unsigned long flags; @@ -126,6 +147,7 @@ struct wifi_capability { wifi_device_handle device; unsigned long flags; + unsigned long capability; /* WIFI_CAPABILITY_RADIOSUPPORTED */ unsigned long radiosupported; @@ -142,6 +164,18 @@ struct wifi_capability { /* WIFI_CAPABILITY_CIPHERS */ struct capwap_array* ciphers; + + /* WIFI_CAPABILITY_MAX_SCAN_SSIDS */ + uint8_t maxscanssids; + + /* WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS */ + uint8_t maxschedscanssids; + + /* WIFI_CAPABILITY_MAX_MATCH_SETS */ + uint8_t maxmatchsets; + + /* WIFI_CAPABILITY_MAX_ACL_MACADDRESS */ + uint8_t maxaclmacaddress; }; /* Frequency configuration */ @@ -172,15 +206,15 @@ struct wifi_driver_ops { /* Device functions */ wifi_device_handle (*device_init)(wifi_global_handle handle, struct device_init_params* params); int (*device_getfdevent)(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events); - int (*device_getcapability)(wifi_device_handle handle, struct wifi_capability* capability); + const struct wifi_capability* (*device_getcapability)(wifi_device_handle handle); int (*device_setfrequency)(wifi_device_handle handle, struct wifi_frequency* freq); void (*device_deinit)(wifi_device_handle handle); /* WLAN functions */ wifi_wlan_handle (*wlan_create)(wifi_device_handle handle, struct wlan_init_params* params); int (*wlan_getfdevent)(wifi_wlan_handle handle, struct pollfd* fds, struct wifi_event* events); - int (*wlan_setupap)(wifi_wlan_handle handle, struct wlan_setupap_params* params); - int (*wlan_startap)(wifi_wlan_handle handle); + int (*wlan_setupap)(wifi_wlan_handle handle); + int (*wlan_startap)(wifi_wlan_handle handle, struct wlan_startap_params* params); int (*wlan_stopap)(wifi_wlan_handle handle); int (*wlan_getmacaddress)(wifi_wlan_handle handle, uint8_t* address); void (*wlan_delete)(wifi_wlan_handle handle); @@ -199,15 +233,12 @@ struct wifi_device { struct capwap_array* wlan; /* Virtual AP */ - /* Cache capability */ - struct wifi_capability* capability; - /* Current frequency */ struct wifi_frequency currentfreq; /* Supported Rates */ int supportedratescount; - uint8_t supportedrates[WIFI_SUPPORTEDRATE_MAX_COUNT]; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; }; /* */ @@ -225,12 +256,12 @@ int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); /* */ int wifi_device_connect(int radioid, const char* ifname, const char* driver); -struct wifi_capability* wifi_device_getcapability(int radioid); +const struct wifi_capability* wifi_device_getcapability(int radioid); int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel); /* */ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid); -int wifi_wlan_setupap(struct capwap_80211_addwlan_element* addwlan, struct capwap_array* ies); +int wifi_wlan_setupap(int radioid, int wlanid); int wifi_wlan_startap(int radioid, int wlanid); int wifi_wlan_stopap(int radioid, int wlanid); int wifi_wlan_getbssid(int radioid, int wlanid, uint8_t* bssid); @@ -239,7 +270,19 @@ void wifi_wlan_destroy(int radioid, int wlanid); /* Util functions */ uint32_t wifi_iface_index(const char* ifname); int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr); -unsigned long wifi_frequency_to_channel(unsigned long freq); + +int wifi_frequency_to_radiotype(uint32_t freq); +unsigned long wifi_frequency_to_channel(uint32_t freq); +int wifi_is_broadcast_addr(const uint8_t* addr); + +/* */ +#define WIFI_VALID_SSID 1 +#define WIFI_WILDCARD_SSID 0 +#define WIFI_WRONG_SSID -1 +int wifi_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist); + +/* */ +int wifi_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length); int wifi_iface_updown(int sock, const char* ifname, int up); #define wifi_iface_up(sock, ifname) wifi_iface_updown(sock, ifname, 1) diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index 6f50505..53a27b6 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -11,7 +11,6 @@ #include "wifi_drivers.h" #include "wifi_nl80211.h" -#include "ieee80211.h" /* Compatibility functions */ #if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30) @@ -88,29 +87,15 @@ static int nl80211_ack_handler(struct nl_msg* msg, void* arg) { } /* */ -static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { - /* TODO */ - return NL_SKIP; -} - -/* */ -static void nl80211_event_receive(int fd, void* param1, void* param2) { - int res; - struct nl_sock* nl = (struct nl_sock*)param1; - struct nl_cb* nl_cb = (struct nl_cb*)param2; +static int nl80211_cookie_handler(struct nl_msg* msg, void* arg) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); /* */ - res = nl_recvmsgs(nl, nl_cb); - if (res) { - capwap_logging_warning("Receive nl80211 message failed: %d", res); + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + if (tb_msg[NL80211_ATTR_COOKIE]) { + *(uint64_t*)arg = nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]); } -} - -/* */ -static int nl80211_global_valid_handler(struct nl_msg* msg, void* arg) { - /* TODO */ - capwap_logging_debug("nl80211_global_valid_handler"); - /* TODO */ return NL_SKIP; } @@ -156,6 +141,247 @@ static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data); } +/* */ +static int nl80211_wlan_send_frame(wifi_wlan_handle handle, struct wlan_send_frame_params* params) { + int result; + uint64_t cookie; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_FRAME, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); + + if (params->frequency) { + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->frequency); + } + + if (params->duration) { + nla_put_u32(msg, NL80211_ATTR_DURATION, params->duration); + } + + if (params->offchannel_tx_ok && (wlanhandle->devicehandle->capability->capability & WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK)) { + nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + } + + if (params->no_cck_rate) { + nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE); + } + + if (params->no_wait_ack) { + nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); + } + + nla_put(msg, NL80211_ATTR_FRAME, params->length, params->packet); + + /* Send frame */ + cookie = 0; + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, nl80211_cookie_handler, &cookie); + nlmsg_free(msg); + + params->cookie = (result || params->no_wait_ack ? 0 : cookie); + + return result; +} + +/* */ +static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + int ssidcheck; + char buffer[IEEE80211_MTU]; + int responselength; + struct ieee80211_ie_items ieitems; + struct wlan_send_frame_params wlan_params; + struct ieee80211_probe_response_params ieee80211_params; + + /* Information Elements packet length */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); + if (ielength < 0) { + return; + } + + /* Parsing Information Elements */ + if (wifi_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { + return; + } + + /* Validate Probe Request Packet */ + if (!ieitems.ssid || !ieitems.supported_rates) { + return; + } + + /* Verify the SSID */ + ssidcheck = wifi_is_valid_ssid(wlanhandle->ssid, ieitems.ssid, ieitems.ssid_list); + if (ssidcheck == WIFI_WRONG_SSID) { + return; + } + + /* Create probe response */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_probe_response_params)); + memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); + ieee80211_params.beaconperiod = wlanhandle->beaconperiod; + ieee80211_params.capability = wlanhandle->capability; + ieee80211_params.ssid = wlanhandle->ssid; + memcpy(ieee80211_params.supportedrates, wlanhandle->supportedrates, wlanhandle->supportedratescount); + ieee80211_params.supportedratescount = wlanhandle->supportedratescount; + ieee80211_params.erpmode = 0; /* TODO */ + ieee80211_params.channel = wifi_frequency_to_channel(wlanhandle->devicehandle->currentfrequency); + + responselength = ieee80211_create_probe_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); + if (responselength < 0) { + return; + } + + /* Send probe response */ + memset(&wlan_params, 0, sizeof(struct wlan_send_frame_params)); + wlan_params.packet = buffer; + wlan_params.length = responselength; + wlan_params.frequency = wlanhandle->devicehandle->currentfrequency; + wlan_params.no_wait_ack = ((ssidcheck == WIFI_WILDCARD_SSID) && wifi_is_broadcast_addr(mgmt->da) ? 1 : 0); + + if (nl80211_wlan_send_frame((wifi_wlan_handle)wlanhandle, &wlan_params)) { + capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); + } +} + +/* */ +static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, uint16_t framecontrol_subtype, int mgmtlength, uint32_t frequency) { + int broadcast; + + /* Check frequency */ + if (frequency && (wlanhandle->devicehandle->currentfrequency != frequency)) { + return; + } + + /* Check if sent packet to correct virtual ap */ + broadcast = wifi_is_broadcast_addr(mgmt->bssid); + if (!broadcast && memcmp(mgmt->bssid, wlanhandle->address, ETH_ALEN)) { + return; + } + + /* */ + if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQ) { + nl80211_do_mgmt_probe_request_event(wlanhandle, mgmt, mgmtlength); + } else if (!memcmp(mgmt->da, wlanhandle->address, ETH_ALEN)) { + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTH: { + /* TODO */ + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOC_REQ: { + /* TODO */ + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOC_REQ: { + /* TODO */ + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOC: { + /* TODO */ + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTH: { + /* TODO */ + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { + /* TODO */ + break; + } + } + } +} + +/* */ +static void nl80211_do_frame_event(struct nl80211_wlan_handle* wlanhandle, struct nlattr* frame, uint32_t frequency) { + const uint8_t* framedata; + const struct ieee80211_header* header; + int framelength; + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + /* */ + if (!frame) { + return; + } + + /* Get frame data */ + framedata = nla_data(frame); + framelength = nla_len(frame); + if (framelength < sizeof(struct ieee80211_header)) { + return; + } + + /* Get type frame */ + header = (const struct ieee80211_header*)framedata; + framecontrol = __le16_to_cpu(header->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) { + nl80211_do_mgmt_frame_event(wlanhandle, (const struct ieee80211_header_mgmt*)framedata, framecontrol_subtype, framelength, frequency); + } +} + +/* */ +static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)arg; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: { + uint32_t frequency = 0; + + if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { + frequency = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); + } + + nl80211_do_frame_event(wlanhandle, tb_msg[NL80211_ATTR_FRAME], frequency); + break; + } + } + + return NL_SKIP; +} + +/* */ +static void nl80211_event_receive(int fd, void* param1, void* param2) { + int res; + struct nl_sock* nl = (struct nl_sock*)param1; + struct nl_cb* nl_cb = (struct nl_cb*)param2; + + /* */ + res = nl_recvmsgs(nl, nl_cb); + if (res) { + capwap_logging_warning("Receive nl80211 message failed: %d", res); + } +} + +/* */ +static int nl80211_global_valid_handler(struct nl_msg* msg, void* arg) { + /* TODO */ + capwap_logging_debug("nl80211_global_valid_handler"); + /* TODO */ + + return NL_SKIP; +} + /* */ static unsigned long nl80211_get_cipher(uint32_t chiper) { switch (chiper) { @@ -330,6 +556,43 @@ static int cb_get_phydevice_capability(struct nl_msg* msg, void* data) { } } + /* */ + if (tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { + capability->flags |= WIFI_CAPABILITY_MAX_SCAN_SSIDS; + capability->maxscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + } + + if (tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) { + capability->flags |= WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS; + capability->maxschedscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); + } + + if (tb_msg[NL80211_ATTR_MAX_MATCH_SETS]) { + capability->flags |= WIFI_CAPABILITY_MAX_MATCH_SETS; + capability->maxmatchsets = nla_get_u8(tb_msg[NL80211_ATTR_MAX_MATCH_SETS]); + } + + if (tb_msg[NL80211_ATTR_MAC_ACL_MAX]) { + capability->flags |= WIFI_CAPABILITY_MAX_ACL_MACADDRESS; + capability->maxaclmacaddress = nla_get_u8(tb_msg[NL80211_ATTR_MAC_ACL_MAX]); + } + + if (tb_msg[NL80211_ATTR_OFFCHANNEL_TX_OK]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK; + } + + if (tb_msg[NL80211_ATTR_ROAM_SUPPORT]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT; + } + + if (tb_msg[NL80211_ATTR_SUPPORT_AP_UAPSD]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD; + } + + if (tb_msg[NL80211_ATTR_DEVICE_AP_SME]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME; + } + /* Cipher supported */ if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) { int count; @@ -575,6 +838,43 @@ static int nl80211_registerframe(struct nl80211_wlan_handle* wlanhandle, uint16_ return result; } +/* */ +static int nl80211_device_getcapability(struct nl80211_device_handle* devicehandle) { + int result; + struct nl_msg* msg; + + ASSERT(devicehandle != NULL); + + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_WIPHY, 0); + nla_put_u32(msg, NL80211_ATTR_WIPHY, devicehandle->phyindex); + + /* Retrieve physical device capability */ + devicehandle->capability->device = (wifi_device_handle)devicehandle; + result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, cb_get_phydevice_capability, devicehandle->capability); + if (result) { + capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static const struct wifi_capability* nl80211_device_getcachedcapability(wifi_device_handle handle) { + struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(devicehandle->capability != NULL); + + return devicehandle->capability; +} + /* */ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct device_init_params* params) { int result; @@ -601,9 +901,19 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct memset(devicehandle, 0, sizeof(struct nl80211_device_handle)); /* */ + devicehandle->globalhandle = globalhandle; strcpy(devicehandle->phyname, phyitem->name); devicehandle->phyindex = phyitem->index; + /* Device capability */ + devicehandle->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability)); + memset(devicehandle->capability, 0, sizeof(struct wifi_capability)); + + devicehandle->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1); + devicehandle->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1); + + /* Retrieve device capability */ + nl80211_device_getcapability(devicehandle); break; } @@ -621,9 +931,6 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct return NULL; } - /* */ - devicehandle->globalhandle = globalhandle; - /* Remove all virtual adapter from wifi device */ nl80211_destroy_all_virtdevice(globalhandle, devicehandle->phyindex); @@ -636,41 +943,12 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct } /* */ -int nl80211_device_getfdevent(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events) { +static int nl80211_device_getfdevent(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events) { return 0; } /* */ -int nl80211_device_getcapability(wifi_device_handle handle, struct wifi_capability* capability) { - int result; - struct nl_msg* msg; - struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; - - ASSERT(handle != NULL); - ASSERT(capability != NULL); - - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_WIPHY, 0); - nla_put_u32(msg, NL80211_ATTR_WIPHY, devicehandle->phyindex); - - /* Retrieve physical device capability */ - capability->device = (wifi_device_handle)devicehandle; - result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, cb_get_phydevice_capability, capability); - if (result) { - capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency* freq) { +static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency* freq) { int result; struct nl_msg* msg; struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; @@ -689,7 +967,9 @@ int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency /* Set wifi frequency */ result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); - if (result) { + if (!result) { + devicehandle->currentfrequency = freq->frequency; + } else { capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); } @@ -700,6 +980,7 @@ int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency /* */ static void nl80211_device_deinit(wifi_device_handle handle) { + int i; struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; if (devicehandle) { @@ -720,6 +1001,31 @@ static void nl80211_device_deinit(wifi_device_handle handle) { search = search->next; } + /* Free capability */ + if (devicehandle->capability) { + if (devicehandle->capability->bands) { + for (i = 0; i < devicehandle->capability->bands->count; i++) { + struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(devicehandle->capability->bands, i); + + if (bandcap->freq) { + capwap_array_free(bandcap->freq); + } + + if (bandcap->rate) { + capwap_array_free(bandcap->rate); + } + } + + capwap_array_free(devicehandle->capability->bands); + } + + if (devicehandle->capability->ciphers) { + capwap_array_free(devicehandle->capability->ciphers); + } + + capwap_free(devicehandle->capability); + } + /* */ capwap_free(devicehandle); } @@ -731,14 +1037,6 @@ static void nl80211_wlan_delete(wifi_wlan_handle handle) { ASSERT(handle != NULL); - if (wlanhandle->headbeacon) { - capwap_free(wlanhandle->headbeacon); - } - - if (wlanhandle->tailbeaconlength) { - capwap_free(wlanhandle->tailbeacon); - } - if (wlanhandle->virtindex) { nl80211_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlanhandle->virtindex); } @@ -820,7 +1118,7 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl } nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); - nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_process_bss_event, NULL); + nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_process_bss_event, (void*)wlanhandle); wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); if (wlanhandle->nl) { @@ -854,7 +1152,7 @@ static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, } /* */ -static int nl80211_wlan_setupap(wifi_wlan_handle handle, struct wlan_setupap_params* params) { +static int nl80211_wlan_setupap(wifi_wlan_handle handle) { int i; struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; static const int stypes[] = { @@ -871,34 +1169,20 @@ static int nl80211_wlan_setupap(wifi_wlan_handle handle, struct wlan_setupap_par /* Register frames */ for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { - nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (stypes[i] << 4), NULL, 0); + if (nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (stypes[i] << 4), NULL, 0)) { + return -1; + } } - /* Save wireless configuration */ - wlanhandle->headbeaconlength = params->headbeaconlength; - if (params->headbeaconlength) { - wlanhandle->headbeacon = capwap_clone(params->headbeacon, params->headbeaconlength); - } - - wlanhandle->tailbeaconlength = params->tailbeaconlength; - if (params->tailbeaconlength) { - wlanhandle->tailbeacon = capwap_clone(params->tailbeacon, params->tailbeaconlength); - } - - strcpy(wlanhandle->ssid, params->ssid); - wlanhandle->suppressssid = (params->suppressssid ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE); - - wlanhandle->beaconinterval = (uint32_t)params->beaconinterval; - wlanhandle->dtimperiod = (uint32_t)params->dtimperiod; - wlanhandle->authenticationtype = ((params->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM); - return 0; } /* */ -static int nl80211_wlan_startap(wifi_wlan_handle handle) { +static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_params* params) { int result; struct nl_msg* msg; + char buffer[IEEE80211_MTU]; + struct ieee80211_beacon_params ieee80211_params; struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; /* Enable interface */ @@ -906,6 +1190,30 @@ static int nl80211_wlan_startap(wifi_wlan_handle handle) { return -1; } + /* Create beacon packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_beacon_params)); + memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); + ieee80211_params.beaconperiod = params->beaconperiod; + ieee80211_params.capability = params->capability; + ieee80211_params.ssid = params->ssid; + ieee80211_params.ssid_hidden = params->ssid_hidden; + memcpy(ieee80211_params.supportedrates, params->supportedrates, params->supportedratescount); + ieee80211_params.supportedratescount = params->supportedratescount; + ieee80211_params.erpmode = 0; /* TODO */ + ieee80211_params.channel = wifi_frequency_to_channel(wlanhandle->devicehandle->currentfrequency); + + result = ieee80211_create_beacon(buffer, IEEE80211_MTU, &ieee80211_params); + if (result < 0) { + return -1; + } + + /* */ + strcpy(wlanhandle->ssid, params->ssid); + wlanhandle->beaconperiod = params->beaconperiod; + wlanhandle->capability = params->capability; + memcpy(wlanhandle->supportedrates, params->supportedrates, params->supportedratescount); + wlanhandle->supportedratescount = params->supportedratescount; + /* */ msg = nlmsg_alloc(); if (!msg) { @@ -915,13 +1223,13 @@ static int nl80211_wlan_startap(wifi_wlan_handle handle) { /* */ genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_START_AP, 0); nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->virtindex); - nla_put(msg, NL80211_ATTR_BEACON_HEAD, wlanhandle->headbeaconlength, wlanhandle->headbeacon); - nla_put(msg, NL80211_ATTR_BEACON_TAIL, wlanhandle->tailbeaconlength, wlanhandle->tailbeacon); - nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL, wlanhandle->beaconinterval); - nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, wlanhandle->dtimperiod); - nla_put(msg, NL80211_ATTR_SSID, strlen(wlanhandle->ssid), wlanhandle->ssid); - nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, wlanhandle->suppressssid); - nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, wlanhandle->authenticationtype); + nla_put(msg, NL80211_ATTR_BEACON_HEAD, ieee80211_params.headbeaconlength, ieee80211_params.headbeacon); + nla_put(msg, NL80211_ATTR_BEACON_TAIL, ieee80211_params.tailbeaconlength, ieee80211_params.tailbeacon); + nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beaconperiod); + nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtimperiod); + nla_put(msg, NL80211_ATTR_SSID, strlen(params->ssid), params->ssid); + nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, (params->ssid_hidden ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE)); + nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, ((params->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM)); nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); /* Start AP */ @@ -960,7 +1268,7 @@ static int nl80211_wlan_stopap(wifi_wlan_handle handle) { } /* */ -int nl80211_wlan_getmacaddress(wifi_wlan_handle handle, uint8_t* address) { +static int nl80211_wlan_getmacaddress(wifi_wlan_handle handle, uint8_t* address) { struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; ASSERT(handle != NULL); @@ -1059,7 +1367,7 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = { .global_deinit = nl80211_global_deinit, .device_init = nl80211_device_init, .device_getfdevent = nl80211_device_getfdevent, - .device_getcapability = nl80211_device_getcapability, + .device_getcapability = nl80211_device_getcachedcapability, .device_setfrequency = nl80211_device_setfrequency, .device_deinit = nl80211_device_deinit, .wlan_create = nl80211_wlan_create, diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index d4d7c13..958d323 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -26,6 +26,10 @@ struct nl80211_device_handle { uint32_t phyindex; char phyname[IFNAMSIZ]; + + uint32_t currentfrequency; + + struct wifi_capability* capability; /* Cached capability */ }; /* WLAN handle */ @@ -41,19 +45,14 @@ struct nl80211_wlan_handle { uint8_t address[ETH_ALEN]; - /* Beacon / Probe response */ - void* headbeacon; - int headbeaconlength; - void* tailbeacon; - int tailbeaconlength; - + /* WLAN information */ char ssid[WIFI_SSID_MAX_LENGTH + 1]; - uint32_t suppressssid; - uint32_t beaconinterval; - uint32_t dtimperiod; + uint16_t beaconperiod; + uint16_t capability; - uint32_t authenticationtype; + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; }; /* Physical device info */ diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index c4a47b2..2f6ec83 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -750,7 +750,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) { configSetting = config_lookup(config, "application.radio"); if (configSetting != NULL) { struct wtp_radio* radio; - struct wifi_capability* capability; + const struct wifi_capability* capability; int count = config_setting_length(configSetting); if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index cc9a0b5..d2f4438 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -102,8 +102,77 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { /* */ binding = GET_WBID_HEADER(packet->rxmngpacket->header); if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { - struct capwap_list_item* search = packet->messages->first; + struct capwap_list_item* search; + /* Set radio configuration and invalidate the old values */ + search = packet->messages->first; + while (search) { + struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; + + /* Parsing only IEEE 802.11 message element */ + if (IS_80211_MESSAGE_ELEMENTS(messageelement->type)) { + switch (messageelement->type) { + case CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_directsequencecontrol_element* directsequencecontrol; + + for (i = 0; i < messageelements->count; i++) { + directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(directsequencecontrol->radioid); + if (radio) { + memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); + memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_OFDMCONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_ofdmcontrol_element* ofdmcontrol; + + for (i = 0; i < messageelements->count; i++) { + ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(ofdmcontrol->radioid); + if (radio) { + memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); + memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_wtpradioinformation_element* radioinformation; + + for (i = 0; i < messageelements->count; i++) { + radioinformation = *(struct capwap_80211_wtpradioinformation_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(radioinformation->radioid); + if (radio && (radio->radioid == radioinformation->radioid)) { + memcpy(&radio->radioinformation, radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); + } + } + } + + break; + } + } + } + + /* Next */ + search = search->next; + } + + /* Update new values */ + search = packet->messages->first; while (search) { struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; @@ -170,7 +239,15 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); radio = wtp_radio_get_phy(directsequencecontrol->radioid); if (radio && (radio->radioid == directsequencecontrol->radioid)) { + if (!(radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G))) { + return -1; + } + + /* Configure radio channel */ memcpy(&radio->directsequencecontrol, directsequencecontrol, sizeof(struct capwap_80211_directsequencecontrol_element)); + if (wifi_device_setfrequency(radio->radioid, WIFI_BAND_2GHZ, radio->radioinformation.radiotype, radio->directsequencecontrol.currentchannel)) { + return -1; + } } } } @@ -187,7 +264,15 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); radio = wtp_radio_get_phy(ofdmcontrol->radioid); if (radio && (radio->radioid == ofdmcontrol->radioid)) { + if (!(radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A)) { + return -1; + } + + /* Configure radio channel */ memcpy(&radio->ofdmcontrol, ofdmcontrol, sizeof(struct capwap_80211_ofdmcontrol_element)); + if (wifi_device_setfrequency(radio->radioid, WIFI_BAND_5GHZ, radio->radioinformation.radiotype, radio->ofdmcontrol.currentchannel)) { + return -1; + } } } } @@ -263,23 +348,6 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { break; } - case CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_wtpradioinformation_element* radioinformation; - - for (i = 0; i < messageelements->count; i++) { - radioinformation = *(struct capwap_80211_wtpradioinformation_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(radioinformation->radioid); - if (radio && (radio->radioid == radioinformation->radioid)) { - memcpy(&radio->radioinformation, radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); - } - } - } - - break; - } - case CAPWAP_ELEMENT_80211_WTP_RADIO_CONF: { messageelements = (struct capwap_array*)messageelement->data; if (messageelements && (messageelements->count > 0)) { @@ -395,16 +463,12 @@ static void wtp_radio_update_fdevent(void) { /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { - uint32_t band; - uint8_t channel; struct wtp_radio* radio; struct wtp_radio_wlan* wlan; struct capwap_80211_addwlan_element* addwlan; - struct capwap_array* ies; /* Get message elements */ addwlan = (struct capwap_80211_addwlan_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_ADD_WLAN); - ies = (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE); if (!addwlan) { return CAPWAP_RESULTCODE_FAILURE; } @@ -428,13 +492,6 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa } } - /* Set radio channel */ - band = ((radio->radioid == radio->directsequencecontrol.radioid) ? WIFI_BAND_2GHZ : WIFI_BAND_5GHZ); - channel = ((radio->radioid == radio->directsequencecontrol.radioid) ? radio->directsequencecontrol.currentchannel : radio->ofdmcontrol.currentchannel); - if (wifi_device_setfrequency(addwlan->radioid, band, radio->radioinformation.radiotype, channel)) { - return CAPWAP_RESULTCODE_FAILURE; - } - /* Set virtual interface information */ wlan = (struct wtp_radio_wlan*)capwap_array_get_item_pointer(radio->wlan, radio->wlan->count); wlan->radio = radio; @@ -453,8 +510,20 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa return CAPWAP_RESULTCODE_FAILURE; } + /* Save wlan configuration */ + wlan->capability = addwlan->capability; + wlan->qos = addwlan->qos; + wlan->authmode = addwlan->authmode; + wlan->macmode = addwlan->macmode; + wlan->tunnelmode = addwlan->tunnelmode; + wlan->ssid_hidden = addwlan->suppressssid; + strcpy(wlan->ssid, (const char*)addwlan->ssid); + wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, wlan->bssid); + + /* TODO (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE) */ + /* Configure virtual interface */ - if (!wifi_wlan_setupap(addwlan, ies)) { + if (!wifi_wlan_setupap(addwlan->radioid, addwlan->wlanid)) { wlan->state = WTP_RADIO_WLAN_STATE_READY; } else { wtp_radio_destroy_wlan(wlan); @@ -475,7 +544,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa /* Retrieve macaddress of new device */ bssid->radioid = addwlan->radioid; bssid->wlanid = addwlan->wlanid; - wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, bssid->bssid); + memcpy(bssid->bssid, wlan->bssid, ETH_ALEN); return CAPWAP_RESULTCODE_SUCCESS; } diff --git a/src/wtp/wtp_radio.h b/src/wtp/wtp_radio.h index 4f3b471..cbcf1ef 100644 --- a/src/wtp/wtp_radio.h +++ b/src/wtp/wtp_radio.h @@ -1,6 +1,8 @@ #ifndef __WTP_RADIO_HEADER__ #define __WTP_RADIO_HEADER__ +#include "ieee80211.h" + /* */ #define WTP_RADIO_ENABLED 0 #define WTP_RADIO_DISABLED 1 @@ -18,11 +20,20 @@ struct wtp_radio_wlan { struct wtp_radio* radio; + int state; uint8_t wlanid; char wlanname[IFNAMSIZ]; + uint8_t bssid[ETH_ALEN]; - int state; + /* */ + uint16_t capability; + uint8_t qos; + uint8_t authmode; + uint8_t macmode; + uint8_t tunnelmode; + uint8_t ssid_hidden; + char ssid[IEEE80211_IE_SSID_MAX_LENGTH + 1]; }; /* */