diff --git a/src/common/binding/ieee80211/ieee80211.h b/src/common/binding/ieee80211/ieee80211.h index f5795be..17d5c31 100644 --- a/src/common/binding/ieee80211/ieee80211.h +++ b/src/common/binding/ieee80211/ieee80211.h @@ -423,6 +423,23 @@ struct ieee80211_ie_erp { /* 802.11 RSN information element */ #define IEEE80211_IE_RSN_INFORMATION 48 + +/* cipher suite selectors */ +#define IEEE80211_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define IEEE80211_CIPHER_SUITE_WEP40 0x000FAC01 +#define IEEE80211_CIPHER_SUITE_TKIP 0x000FAC02 +/* reserved: 0x000FAC03 */ +#define IEEE80211_CIPHER_SUITE_CCMP 0x000FAC04 +#define IEEE80211_CIPHER_SUITE_WEP104 0x000FAC05 +#define IEEE80211_CIPHER_SUITE_AES_CMAC 0x000FAC06 +#define IEEE80211_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07 +#define IEEE80211_CIPHER_SUITE_GCMP 0x000FAC08 +#define IEEE80211_CIPHER_SUITE_GCMP_256 0x000FAC09 +#define IEEE80211_CIPHER_SUITE_CCMP_256 0x000FAC0A +#define IEEE80211_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B +#define IEEE80211_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C +#define IEEE80211_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D + /* 802.11 Extended Supported Rates information element */ #define IEEE80211_IE_EXTENDED_SUPPORTED_RATES 50 #define IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH 1 diff --git a/src/common/capwap_element.c b/src/common/capwap_element.c index c3af749..e462f72 100644 --- a/src/common/capwap_element.c +++ b/src/common/capwap_element.c @@ -94,7 +94,8 @@ static const struct capwap_message_elements_ops * capwap_vendor_travelping_messa element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_WTP_TIMESTAMP_TYPE, capwap_element_vendor_travelping_wtp_timestamp_ops), element_ops(CAPWAP_ELEMENT_80211N_RADIO_CONF_TYPE, capwap_element_80211n_radioconf_ops), element_ops(CAPWAP_ELEMENT_80211N_STATION_INFO_TYPE, capwap_element_80211n_station_info_ops), - element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_ENCRYPTION_CAPABILITY_TYPE, capwap_element_vendor_travelping_80211_encryption_capability_ops) + element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_ENCRYPTION_CAPABILITY_TYPE, capwap_element_vendor_travelping_80211_encryption_capability_ops), + element_ops(CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE, capwap_element_vendor_travelping_80211_update_key_ops) }; #undef element_ops diff --git a/src/common/capwap_element_vendor_travelping_80211_update_key.c b/src/common/capwap_element_vendor_travelping_80211_update_key.c new file mode 100644 index 0000000..8a190d9 --- /dev/null +++ b/src/common/capwap_element_vendor_travelping_80211_update_key.c @@ -0,0 +1,108 @@ +#include "capwap.h" +#include "capwap_element.h" + +/* + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Radio ID | WLAN ID | Key Index | Key Status | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cipher Suite | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Key... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * IEEE 802.11 Update Key + * + * Vendor Id: 18681 (Travelping GmbH) + * Type: 19 + * + * Length: >= 6 + * + */ + +/* */ +static void +capwap_vendor_travelping_80211_update_key_element_create(void *data, + capwap_message_elements_handle handle, + struct capwap_write_message_elements_ops *func) +{ + struct capwap_vendor_travelping_80211_update_key_element *element = + (struct capwap_vendor_travelping_80211_update_key_element*)data; + + ASSERT(data != NULL); + + func->write_u8(handle, element->radioid); + func->write_u8(handle, element->wlanid); + func->write_u8(handle, element->keyindex); + func->write_u8(handle, element->keystatus); + func->write_u32(handle, element->ciphersuite); + if (element->keylength > 0) + func->write_block(handle, element->key, element->keylength); +} + +/* */ +static void * +capwap_vendor_travelping_80211_update_key_element_parsing(capwap_message_elements_handle handle, + struct capwap_read_message_elements_ops *func) +{ + unsigned short length; + struct capwap_vendor_travelping_80211_update_key_element *data; + + ASSERT(handle != NULL); + ASSERT(func != NULL); + + length = func->read_ready(handle); + if (length < 8) { + log_printf(LOG_DEBUG, "Invalid Vendor Travelping IEEE 802.11 Update Key element"); + return NULL; + } + + length -= 8; + + /* */ + data = (struct capwap_vendor_travelping_80211_update_key_element *) + capwap_alloc(sizeof(struct capwap_vendor_travelping_80211_update_key_element) + length); + memset(data, 0, sizeof(struct capwap_vendor_travelping_80211_update_key_element) + length); + + /* Retrieve data */ + func->read_u8(handle, &data->radioid); + func->read_u8(handle, &data->wlanid); + func->read_u8(handle, &data->keyindex); + func->read_u8(handle, &data->keystatus); + func->read_u32(handle, &data->ciphersuite); + data->keylength = length; + func->read_block(handle, data->key, data->keylength); + + return data; +} + +/* */ +static void *capwap_vendor_travelping_80211_update_key_element_clone(void *data) +{ + struct capwap_vendor_travelping_80211_update_key_element *element = + (struct capwap_vendor_travelping_80211_update_key_element*)data; + + ASSERT(data != NULL); + + return capwap_clone(data, sizeof(struct capwap_vendor_travelping_80211_update_key_element) + + element->keylength); +} + +/* */ +static void capwap_vendor_travelping_80211_update_key_element_free(void *data) +{ + ASSERT(data != NULL); + + capwap_free(data); +} + +/* */ +const struct capwap_message_elements_ops capwap_element_vendor_travelping_80211_update_key_ops = { + .category = CAPWAP_MESSAGE_ELEMENT_ARRAY, + .create = capwap_vendor_travelping_80211_update_key_element_create, + .parse = capwap_vendor_travelping_80211_update_key_element_parsing, + .clone = capwap_vendor_travelping_80211_update_key_element_clone, + .free = capwap_vendor_travelping_80211_update_key_element_free +}; diff --git a/src/common/capwap_element_vendor_travelping_80211_update_key.h b/src/common/capwap_element_vendor_travelping_80211_update_key.h new file mode 100644 index 0000000..d411cc7 --- /dev/null +++ b/src/common/capwap_element_vendor_travelping_80211_update_key.h @@ -0,0 +1,27 @@ +#ifndef __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__ +#define __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__ + +#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_VENDOR CAPWAP_VENDOR_TRAVELPING_ID +#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE 19 +#define CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY \ + (struct capwap_message_element_id){ \ + .vendor = CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_VENDOR, \ + .type = CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_TYPE \ + } + +#define CAPWAP_UPDATE_WLAN_KEY_STATUS_REKEYING 2 +#define CAPWAP_UPDATE_WLAN_KEY_STATUS_COMPLETE 3 + +struct capwap_vendor_travelping_80211_update_key_element { + uint8_t radioid; + uint8_t wlanid; + uint8_t keyindex; + uint8_t keystatus; + uint32_t ciphersuite; + uint16_t keylength; + uint8_t key[]; +}; + +extern const struct capwap_message_elements_ops capwap_element_vendor_travelping_80211_update_key_ops; + +#endif /* __CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY_HEADER__ */ diff --git a/src/common/capwap_vendor_travelping.h b/src/common/capwap_vendor_travelping.h index 4540857..4be1225 100644 --- a/src/common/capwap_vendor_travelping.h +++ b/src/common/capwap_vendor_travelping.h @@ -5,6 +5,7 @@ #include "capwap_element_vendor_travelping_wtp_timestamp.h" #include "capwap_element_vendor_travelping_80211_encryption_capability.h" +#include "capwap_element_vendor_travelping_80211_update_key.h" /* draft-ietf-opsawg-capwap-extension-06 */ #include "capwap_element_80211n_radioconf.h" diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index 87ee900..6cb6d33 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -2123,6 +2123,41 @@ static struct ieee80211_ie *rsn_from_ie(uint8_t radioid, uint8_t wlanid, 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) { @@ -2167,18 +2202,19 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params /* Start AP */ result = wlan_startap(wlan); - if (!result) { - wlan->device->wlanactive++; - log_printf(LOG_INFO, "Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid); - } else { + 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; } -#define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff" - /* */ int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* params) { @@ -2237,6 +2273,9 @@ int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* para break; } + if (!result) + update_keys(wlan, params->updatekeys); + return result; } diff --git a/src/wtp/binding/ieee80211/wifi_drivers.h b/src/wtp/binding/ieee80211/wifi_drivers.h index 861ab90..441e614 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.h +++ b/src/wtp/binding/ieee80211/wifi_drivers.h @@ -103,6 +103,7 @@ struct wlan_startap_params { uint8_t *key; struct capwap_array *ie; + struct capwap_array *updatekeys; }; struct wlan_updateap_params { @@ -118,6 +119,7 @@ struct wlan_updateap_params { uint8_t *key; struct capwap_array *ie; + struct capwap_array *updatekeys; }; /* */ diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.c b/src/wtp/binding/ieee80211/wifi_nl80211.c index f453ca3..3063a44 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.c +++ b/src/wtp/binding/ieee80211/wifi_nl80211.c @@ -1060,7 +1060,12 @@ static int nl80211_set_key(struct wifi_wlan* wlan, msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_SET_KEY); if (!msg || nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) || - nla_put_flag(msg, NL80211_ATTR_KEY_DEFAULT)) + nla_put_flag(msg, (alg == IEEE80211_CIPHER_SUITE_AES_CMAC || + alg == IEEE80211_CIPHER_SUITE_BIP_GMAC_128 || + alg == IEEE80211_CIPHER_SUITE_BIP_GMAC_256 || + alg == IEEE80211_CIPHER_SUITE_BIP_CMAC_256) ? + NL80211_ATTR_KEY_DEFAULT_MGMT : + NL80211_ATTR_KEY_DEFAULT)) goto fail; types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES); diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index dea5525..3884c04 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -652,6 +652,47 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons } } +static struct capwap_array *wtp_radio_set_update_keys(struct capwap_parsed_packet *packet, + uint8_t radioid, uint8_t wlanid) +{ + int i; + struct capwap_array *keys; + struct capwap_array *updatekeys = NULL; + + ASSERT(packet != NULL); + + keys = (struct capwap_array *) + capwap_get_message_element_data(packet, CAPWAP_ELEMENT_VENDOR_TRAVELPING_80211_UPDATE_KEY); + log_printf(LOG_DEBUG, "Set Update Keys: %p", keys); + if (!keys) + return NULL; + + log_printf(LOG_DEBUG, "Set 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, "RadioId: %d .. %d, WlanId: %d .. %d", + key->radioid, radioid, + key->wlanid, wlanid); + + if (key->radioid != radioid || key->wlanid != wlanid) + continue; + + if (!updatekeys) + updatekeys = capwap_array_create(sizeof(void *), 0, 0); + if (!updatekeys) { + log_printf(LOG_DEBUG, "Update WLAN: Out of Memory"); + return NULL; + } + *(void **)capwap_array_get_item_pointer(updatekeys, updatekeys->count) = key; + log_printf(LOG_DEBUG, "Set Update Keys: Update #%ld", updatekeys->count); + } + + return updatekeys; +} + /* source http://stackoverflow.com/a/16994674 */ static uint16_t reverse(register uint16_t x) { @@ -721,6 +762,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, params.key = addwlan->key; params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE); + params.updatekeys = wtp_radio_set_update_keys(packet, addwlan->radioid, addwlan->wlanid); /* Start AP */ if (wifi_wlan_startap(wlan->wlanhandle, ¶ms)) { @@ -788,6 +830,7 @@ uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet) params.key = updatewlan->key; params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE); + params.updatekeys = wtp_radio_set_update_keys(packet, updatewlan->radioid, updatewlan->wlanid); /* Update AP */ if (wifi_wlan_updateap(wlan->wlanhandle, ¶ms)) {