10 Commits

Author SHA1 Message Date
9fbf441896 release 1.3.0 2016-08-08 09:28:18 +02:00
01919fffd9 update support for group key updates with Update WLAN 2016-08-08 09:25:01 +02:00
02e8d534b5 preserve QoS tid for injected QoS data frames
The TX path will overwrite the TID based on the SKB
priority. Load the QoS TID from 802.11 frames into
the skb priority to preserve it during TX handling.
2016-08-02 15:46:07 +02:00
3626927722 reset timeout_action on assoc response frame
Assoziation is complete when we get a response frame. We need to
reset the timeout action here, otherwise the client gets detached
as soon as the timer fires.
2016-08-01 18:14:00 +02:00
2ac3944e7a implement WPA2 Stations Key handling
Implement the required support for extrace the cipher
suite settings from the the RS Information Element and
set the station key based on the 802.11 Station Key
CAPWAP message element.

Group Key update handling is currently not implemented nor is
Station Key update handling.
2016-07-27 12:36:34 +02:00
a131e17a6e fix 802.11 Station Key IE handling
memsetting the data to zero right after assigning them
is obviously wrong
2016-07-27 12:17:00 +02:00
0e19b53e28 forward PAE (IEEE 802.1X Authentication) frames as raw 802.11 frames to AC 2016-05-10 17:07:46 +02:00
9ded0bb87b release 1.2.1 2016-05-06 17:58:27 +02:00
b0aaaa4436 replace memcmp on message id struct with direct compare
cset 3761122c fixed one place, but a few others remained.
This should take care of them all and fix a missing
IE in Add WLAN responses.
2016-05-06 17:52:39 +02:00
6024cc15cf fix interpretation of Add WLAN's capability field
RFC 5416 copies the order of the capability flags from the
IEEE 802.11 capability IE. However, the bit ordering assumtions
in RFC 5416 differ from IEEE 802.11 (in the RFC the MSB is
numbered 0, in IEEE 802.11 the MSB is numbere 15).

RFC 5416 therefore specifies the capability flags bit reversed
compared to IEEE 802.11.
2016-05-03 10:28:38 +02:00
20 changed files with 607 additions and 61 deletions

12
NEWS.md
View File

@ -3,6 +3,18 @@ SmartCAPWAP
CAPWAP WTP and AC implementation
Version 1.3.0 - 08 Aug 2016
---------------------------
* forward PAE (IEEE 802.1X Authentication) frames as raw 802.11 frames to AC
* implement encryption support for group and peer temporal keys (CCMP only)
Version 1.2.1 - 06 May 2016
---------------------------
* fix Add WLAN's capability field
* fix mssing IEEE 802.11 Assigned WTP BSSID IE in Add WLAN response
Version 1.2.0 - 29 Apr 2016
---------------------------

View File

@ -17,6 +17,7 @@ NOTE: The WTP has been ported to libev, the AC has not been adjusted and is ther
* Local MAC
* single radio, single WLAN mode
* 802.11n ([draft-ietf-opsawg-capwap-extension-06](https://tools.ietf.org/html/draft-ietf-opsawg-capwap-extension-06))
* WPA2-PSK
Only cards with cfg80211 netlink API are supported. The following devices
have been tested:
@ -26,7 +27,8 @@ have been tested:
### Planned WTP features:
* encryption (WPA2)
* WPA2 Enterprise
* 802.11r - BSS fast transition
* Hybrid-MAC ([RFC-7494](https://tools.ietf.org/html/rfc7494))
## INSTALLATION

View File

@ -19,7 +19,7 @@
AC_PREREQ(2.63)
AC_INIT([SmartCAPWAP], [1.2], [https://github.com/travelping/smartcapwap], [smartcapwap])
AC_INIT([SmartCAPWAP], [1.2.1], [https://github.com/travelping/smartcapwap], [smartcapwap])
AC_CONFIG_AUX_DIR([build])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 -Wall])

View File

@ -9,14 +9,14 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=smartcapwap
PKG_VERSION:=1.2
PKG_VERSION:=1.2.1
PKG_RELEASE:=1
SRC_SMARTCAPWAP := /usr/src/tplino/components/smartcapwap
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=git://github.com/travelping/smartcapwap.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_VERSION:=v1.2.0
PKG_SOURCE_VERSION:=v1.2.1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

View File

@ -1,4 +1,4 @@
From 03b6aa026d60cd49931934338d8ca82d05acc818 Mon Sep 17 00:00:00 2001
From c26411bf0d00a6ceed42e85d66812b591b7c4c83 Mon Sep 17 00:00:00 2001
From: Andreas Schultz <aschultz@tpip.net>
Date: Thu, 4 Feb 2016 15:57:11 +0100
Subject: [PATCH] support patch for smartcapwap
@ -7,10 +7,10 @@ Allows for kernel side interception and injection of IEEE 802.11 frames.
---
include/net/mac80211.h | 25 ++++
net/mac80211/ieee80211_i.h | 6 +
net/mac80211/iface.c | 56 +++++++++
net/mac80211/iface.c | 56 ++++++++
net/mac80211/rx.c | 81 ++++++++++--
net/mac80211/tx.c | 306 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 462 insertions(+), 12 deletions(-)
net/mac80211/tx.c | 312 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 468 insertions(+), 12 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 760bc4d..6722da6 100644
@ -334,10 +334,10 @@ index 82af407..29cc59b 100644
rcu_read_unlock();
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index bdc224d..3769c33 100644
index bdc224d..fd48ccf 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2939,6 +2939,138 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
@@ -2939,6 +2939,144 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
@ -388,6 +388,12 @@ index bdc224d..3769c33 100644
+ payload[7]);
+ }
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *p = ieee80211_get_qos_ctl(hdr);
+
+ skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
@ -476,7 +482,7 @@ index bdc224d..3769c33 100644
struct sk_buff *
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags)
@@ -3914,3 +4046,177 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
@@ -3914,3 +4052,177 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
ieee80211_xmit(sdata, NULL, skb);
local_bh_enable();
}
@ -655,5 +661,5 @@ index bdc224d..3769c33 100644
+EXPORT_SYMBOL(ieee80211_inject_xmit);
+
--
2.7.0
2.8.1

View File

@ -420,6 +420,9 @@ struct ieee80211_ie_erp {
uint8_t params;
} STRUCT_PACKED;
/* 802.11 RSN information element */
#define IEEE80211_IE_RSN_INFORMATION 48
/* 802.11 Extended Supported Rates information element */
#define IEEE80211_IE_EXTENDED_SUPPORTED_RATES 50
#define IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH 1

View File

@ -139,7 +139,7 @@ struct capwap_list_item* capwap_get_message_element(struct capwap_parsed_packet*
while (search) {
struct capwap_message_element_itemlist* messageelement =
(struct capwap_message_element_itemlist*)search->item;
if ((id.vendor == messageelement->id.vendor) && (id.type == messageelement->id.type))
if (message_element_id_eq(id, messageelement->id))
return search;
/* */

View File

@ -10,6 +10,9 @@ struct capwap_message_element_id
uint16_t type;
};
#define message_element_id_eq(a, b) \
(((a).vendor == (b).vendor) && ((a).type == (b).type))
/* */
typedef void* capwap_message_elements_handle;
struct capwap_write_message_elements_ops {

View File

@ -39,7 +39,9 @@ static void capwap_80211_stationkey_element_create(void* data, capwap_message_el
}
/* */
static void* capwap_80211_stationkey_element_parsing(capwap_message_elements_handle handle, struct capwap_read_message_elements_ops* func) {
static void* capwap_80211_stationkey_element_parsing(capwap_message_elements_handle handle,
struct capwap_read_message_elements_ops* func)
{
unsigned short length;
struct capwap_80211_stationkey_element* data;
@ -53,10 +55,11 @@ static void* capwap_80211_stationkey_element_parsing(capwap_message_elements_han
}
/* */
data = (struct capwap_80211_stationkey_element*)capwap_alloc(sizeof(struct capwap_80211_stationkey_element));
data = (struct capwap_80211_stationkey_element *)
capwap_alloc(sizeof(struct capwap_80211_stationkey_element));
memset(data, 0, sizeof(struct capwap_80211_stationkey_element));
data->keylength = length - 20;
data->key = (uint8_t*)capwap_alloc(data->keylength);
memset(data, 0, sizeof(struct capwap_80211_stationkey_element));
/* Retrieve data */
func->read_block(handle, data->address, MACADDRESS_EUI48_LENGTH);

View File

@ -110,6 +110,16 @@ 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);
@ -1342,9 +1352,19 @@ wifi_wlan_receive_station_mgmt_association_response_ack(struct wifi_wlan* wlan,
/* */
station->flags |= WIFI_STATION_FLAGS_ASSOCIATE;
if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) {
int result;
/* Apply authorization if Station already authorized */
if (station_authorize(wlan, station))
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;
}
}
}
@ -2071,6 +2091,39 @@ static int ht_opmode_from_ie(uint8_t radioid, uint8_t wlanid,
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;
}
/* */
int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params)
{
@ -2097,6 +2150,12 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
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,
@ -2119,6 +2178,69 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
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)
{
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;
}
return result;
}
/* */
void wifi_wlan_stopap(struct wifi_wlan* wlan)
{
@ -2334,14 +2456,21 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
station = wifi_station_get(wlan, params->address);
if (!station)
return -1;
if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED)
return 0;
/* 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))
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));
@ -2350,8 +2479,16 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
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);
@ -2360,9 +2497,27 @@ int wifi_station_authorize(struct wifi_wlan* wlan,
/* 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;

View File

@ -71,6 +71,7 @@ DECLARE_OPAQUE_TYPE(wifi_device_handle);
DECLARE_OPAQUE_TYPE(wifi_wlan_handle);
struct capwap_80211_wtpqos_element;
struct capwap_80211_stationkey_element;
/* */
struct device_setrates_params {
@ -106,9 +107,27 @@ struct wlan_startap_params {
uint8_t macmode;
uint8_t tunnelmode;
uint8_t keyindex;
uint8_t keylength;
uint8_t *key;
struct capwap_array *ie;
};
struct wlan_updateap_params {
uint8_t radioid;
uint8_t wlanid;
uint16_t capability;
uint8_t qos;
uint8_t keyindex;
uint8_t keystatus;
uint8_t keylength;
uint8_t *key;
struct capwap_array *ie;
};
/* */
struct wlan_send_frame_params {
@ -128,6 +147,8 @@ struct wlan_send_frame_params {
struct station_add_params {
uint8_t* address;
struct ieee80211_ht_cap *ht_cap;
uint32_t pairwise;
struct capwap_80211_stationkey_element *key;
int max_inactivity;
};
@ -326,6 +347,12 @@ struct wifi_wlan {
uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE];
struct ieee80211_ie *rsne;
uint32_t group_cipher_suite;
uint8_t keyindex;
uint8_t keylength;
uint8_t *key;
int beacon_ies_len;
uint8_t *beacon_ies;
int response_ies_len;
@ -379,6 +406,8 @@ struct wifi_station {
/* Authentication */
uint16_t authalgorithm;
uint32_t pairwise_cipher;
struct capwap_80211_stationkey_element *key;
uint8_t qosinfo;
@ -410,6 +439,11 @@ struct wifi_driver_ops {
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);
void (*wlan_poll_station)(struct wifi_wlan* wlan, const uint8_t* address, int qos);
void (*wlan_delete)(struct wifi_wlan* wlan);
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);
/* Stations functions */
int (*station_authorize)(struct wifi_wlan* wlan, struct wifi_station* station);
@ -435,6 +469,7 @@ int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int rate
/* WLAN management */
struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname);
int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params);
int wifi_wlan_updateap(struct wifi_wlan* wlan, struct wlan_updateap_params* params);
void wifi_wlan_stopap(struct wifi_wlan* wlan);
int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid);
uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability);
@ -448,6 +483,7 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
void wifi_wlan_client_probe_event(struct wifi_wlan *wlan, const uint8_t *address);
/* Station management */
int wifi_station_set_key(struct wifi_wlan *wlan, struct wifi_station* station);
int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params);
void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address);

View File

@ -882,6 +882,50 @@ static int nl80211_wlan_setbeacon(struct wifi_wlan* wlan) {
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
goto out_err;
/* privacy */
if (wlan->rsne)
log_printf(LOG_DEBUG, "RSNE capability: %04x", wlan->capability);
if (wlan->rsne &&
wlan->capability & IEEE80211_CAPABILITY_PRIVACY) {
uint8_t *data = (uint8_t *)(wlan->rsne + 1);
uint16_t suites_num;
uint32_t *suites;
int i;
data += 2;
nla_put_flag(msg, NL80211_ATTR_PRIVACY);
nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, NL80211_WPA_VERSION_2);
log_printf(LOG_ERR, "nl80211: Cipher Suite Group: %08x", ntohl(*(uint32_t *)data));
/* find a better place for the cipher suite assignment */
wlan->group_cipher_suite = ntohl(*(uint32_t *)data);
nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, ntohl(*(uint32_t *)data));
data += sizeof(uint32_t);
suites_num = *(uint16_t *)data;
data += 2;
suites = alloca(suites_num * sizeof(uint32_t));
for (i = 0; i < suites_num; i++) {
suites[i] = ntohl(*(uint32_t *)data);
log_printf(LOG_ERR, "nl80211: Cipher Suite Pairwise[%d]: %08x", i, suites[i]);
data +=sizeof(uint32_t);
}
nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, suites_num * sizeof(uint32_t), suites);
suites_num = *(uint16_t *)data;
data += 2;
suites = alloca(suites_num * sizeof(uint32_t));
for (i = 0; i < suites_num; i++) {
suites[i] = ntohl(*(uint32_t *)data);
log_printf(LOG_ERR, "nl80211: AKM Suite[%d]: %08x", i, suites[i]);
data +=sizeof(uint32_t);
}
nla_put(msg, NL80211_ATTR_AKM_SUITES, suites_num * sizeof(uint32_t), suites);
}
/* Start AP */
result = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
if (result)
@ -931,6 +975,115 @@ out_err:
return -1;
}
static inline int is_broadcast_ether_addr(const uint8_t *a)
{
return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
}
#define broadcast_ether_addr (const uint8_t *) "\xff\xff\xff\xff\xff\xff"
static int nl80211_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)
{
struct nl_msg *msg;
int ret;
log_printf(LOG_DEBUG, "%s: ifindex=%d alg=%08x addr=%p key_idx=%d "
"set_tx=%d seq_len=%lu key_len=%lu",
__func__, wlan->virtindex, alg, addr, key_idx, set_tx,
(unsigned long) seq_len, (unsigned long) key_len);
if (alg == 0) {
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_DEL_KEY);
if (!msg)
return -ENOBUFS;
} else {
msg = nl80211_wlan_msg(wlan, 0, NL80211_CMD_NEW_KEY);
if (!msg ||
nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, alg))
goto fail;
log_hexdump(LOG_DEBUG, "nl80211: KEY_DATA", key, key_len);
}
if (seq && seq_len) {
if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
goto fail;
log_hexdump(LOG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}
if (addr && !is_broadcast_ether_addr(addr)) {
log_printf(LOG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
goto fail;
if (key_idx && !set_tx) {
log_printf(LOG_DEBUG, " RSN IBSS RX GTK");
if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
NL80211_KEYTYPE_GROUP))
goto fail;
}
} else if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
log_printf(LOG_DEBUG, " broadcast key");
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types ||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
nla_nest_end(msg, types);
}
if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
goto fail;
ret = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == 0)
ret = 0;
if (ret)
log_printf(LOG_DEBUG, "nl80211: set_key failed; err=%d %s)",
ret, strerror(-ret));
/*
* If we failed or don't need to set the default TX key (below),
* we're done here.
*/
if (ret || !set_tx || alg == 0)
return ret;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
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))
goto fail;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types ||
nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
nla_nest_end(msg, types);
ret = nl80211_wlan_send_and_recv_msg(wlan, msg, NULL, NULL);
if (ret == -ENOENT)
ret = 0;
if (ret)
log_printf(LOG_DEBUG, "nl80211: set_key default failed; "
"err=%d %s)", ret, strerror(-ret));
}
return ret;
fail:
nlmsg_free(msg);
return -ENOBUFS;
}
/* */
static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
int i;
@ -1006,6 +1159,10 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
return -1;
}
if (wlan->keylength && wlan->key)
nl80211_set_key(wlan, wlan->group_cipher_suite, broadcast_ether_addr,
wlan->keyindex, 1, NULL, 0, wlan->key, wlan->keylength);
/* Enable operation status */
wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING;
netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP);
@ -2282,6 +2439,7 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = {
.wlan_sendframe = nl80211_wlan_sendframe,
.wlan_poll_station = nl80211_wlan_poll_station,
.wlan_delete = nl80211_wlan_delete,
.wlan_set_key = nl80211_set_key,
.station_authorize = nl80211_station_authorize,
.station_deauthorize = nl80211_station_deauthorize,

View File

@ -637,7 +637,16 @@ int sc_capwap_parsingpacket(struct sc_capwap_session* session,
}
/* */
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) {
int sc_capwap_forwarddata(struct sc_capwap_session* session,
uint8_t radioid,
uint8_t binding,
struct sk_buff* skb,
uint32_t flags,
struct sc_capwap_radio_addr* radioaddr,
int radioaddrlength,
struct sc_capwap_wireless_information* winfo,
int winfolength)
{
int err;
int size;
int length;

View File

@ -50,12 +50,15 @@ union capwap_addr {
struct sockaddr_storage ss;
};
#define STA_FLAG_AKM_ONLY 0x0001
struct sc_station {
struct hlist_node station_list;
uint8_t radioid;
uint8_t mac[ETH_ALEN];
uint8_t wlanid;
uint32_t flags;
struct rcu_head rcu_head;
};

View File

@ -169,8 +169,6 @@ static void sc_send_8023(struct sk_buff *skb, struct net_device *dev)
static void sc_send_80211(struct sk_buff *skb, struct net_device *dev)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
int hdrlen;
printk(KERN_DEBUG "capwap inject: %s: hdr: %p\n",
dev->name, skb->data);
@ -185,17 +183,15 @@ static void sc_send_80211(struct sk_buff *skb, struct net_device *dev)
/* drop conntrack reference */
nf_reset(skb);
hdr = (struct ieee80211_hdr *)skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb->dev = dev;
skb_set_mac_header(skb, hdrlen);
skb_set_network_header(skb, hdrlen);
skb_set_transport_header(skb, hdrlen);
skb->protocol = htons(ETH_P_CONTROL);
info->flags |= IEEE80211_TX_CTL_INJECTED;
memset(info, 0, sizeof(*info));
info->flags = IEEE80211_TX_CTL_INJECTED;
/* Force the device to verify it. */
skb->ip_summed = CHECKSUM_NONE;

View File

@ -85,32 +85,58 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb,
int err;
uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
uint8_t winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
uint16_t hdrlen, ethertype;
uint8_t *payload;
struct sc_capwap_radio_addr* radioaddr = NULL;
struct sc_capwap_wireless_information* winfo = NULL;
uint32_t flags = nldev->flags;
/* Drop packet */
ret = -1;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (!pskb_may_pull(skb, hdrlen + 8))
goto error;
payload = skb->data + hdrlen;
ethertype = (payload[6] << 8) | payload[7];
TRACEKMOD("### sc_netlink_handler, ethertype %04x\n", ethertype);
switch (ethertype) {
case ETH_P_PAE:
/* forward EAPOL as raw 802.11 frame, clear 802.3 tunnel flag */
flags &= ~NLSMARTCAPWAP_FLAGS_TUNNEL_8023;
break;
default:
/* IEEE 802.11 into IEEE 802.3 */
if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) {
if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) {
if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP))
goto error;
}
/* Create Radio Mac Address */
radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, nldev->dev->dev_addr);
radioaddr =
sc_capwap_setradiomacaddress(radioaddrbuffer,
CAPWAP_RADIO_EUI48_LENGTH_PADDED,
nldev->dev->dev_addr);
}
break;
}
/* Create Wireless Information */
if (sig_dbm || rate) {
winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
}
if (sig_dbm || rate)
winfo = sc_capwap_setwinfo_frameinfo(winfobuffer,
CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED,
(uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
/* */
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211;
/* Forward to AC */
err = sc_capwap_forwarddata(&sn->sc_acsession, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
err = sc_capwap_forwarddata(&sn->sc_acsession, nldev->radioid, nldev->binding, skb, flags,
radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0),
winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
}
error:
@ -642,7 +668,8 @@ static int sc_netlink_add_station(struct sk_buff* skb, struct genl_info* info)
if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] ||
!info->attrs[NLSMARTCAPWAP_ATTR_MAC] ||
!info->attrs[NLSMARTCAPWAP_ATTR_WLANID])
!info->attrs[NLSMARTCAPWAP_ATTR_WLANID] ||
!info->attrs[NLSMARTCAPWAP_ATTR_FLAGS])
return -EINVAL;
radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
@ -650,12 +677,18 @@ static int sc_netlink_add_station(struct sk_buff* skb, struct genl_info* info)
hash = jhash(mac, ETH_ALEN, radioid) % STA_HASH_SIZE;
sta_head = &session->station_list[hash];
if (sc_find_station(sta_head, radioid, mac) != NULL)
sta = sc_find_station(sta_head, radioid, mac);
if (sta) {
if (!(info->nlhdr->nlmsg_flags & NLM_F_REPLACE))
return -EEXIST;
if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
if (sta->wlanid != nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]))
return -ENXIO;
sta->flags = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]);
return 0;
}
sta = kmalloc(sizeof(struct sc_station), GFP_KERNEL);
if (sta == NULL)
return -ENOMEM;
@ -663,6 +696,7 @@ static int sc_netlink_add_station(struct sk_buff* skb, struct genl_info* info)
sta->radioid = radioid;
memcpy(&sta->mac, mac, ETH_ALEN);
sta->wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]);
sta->flags = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]);
hlist_add_head_rcu(&sta->station_list, sta_head);

View File

@ -242,7 +242,7 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RESULTCODE, &resultcode);
if (resultcode.code == CAPWAP_RESULTCODE_SUCCESS &&
memcmp(&action, &CAPWAP_ELEMENT_80211_ADD_WLAN, sizeof(CAPWAP_ELEMENT_80211_ADD_WLAN)) == 0)
message_element_id_eq(action, CAPWAP_ELEMENT_80211_ADD_WLAN))
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ASSIGN_BSSID, &bssid);
/* CAPWAP_ELEMENT_VENDORPAYLOAD */ /* TODO */

View File

@ -438,7 +438,7 @@ int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) {
}
/* */
int wtp_kmod_add_station(uint8_t radioid, const uint8_t *mac, uint8_t wlanid)
int wtp_kmod_add_station(uint8_t radioid, const uint8_t *mac, uint8_t wlanid, uint32_t flags)
{
int result;
struct nl_msg* msg;
@ -453,10 +453,12 @@ int wtp_kmod_add_station(uint8_t radioid, const uint8_t *mac, uint8_t wlanid)
return -1;
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_ADD_STATION, 0);
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0,
NLM_F_CREATE | NLM_F_REPLACE, NLSMARTCAPWAP_CMD_ADD_STATION, 0);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid);
nla_put(msg, NLSMARTCAPWAP_ATTR_MAC, ETH_ALEN, mac);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlanid);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, wlanid);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);

View File

@ -63,7 +63,10 @@ int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags);
int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan);
/* */
int wtp_kmod_add_station(uint8_t radioid, const uint8_t *mac, uint8_t wlanid);
#define STA_FLAG_AKM_ONLY 0x0001
/* */
int wtp_kmod_add_station(uint8_t radioid, const uint8_t *mac, uint8_t wlanid, uint32_t flags);
int wtp_kmod_del_station(uint8_t radioid, const uint8_t *mac);
#endif /* __WTP_KMOD_HEADER__ */

View File

@ -195,7 +195,7 @@ static void wtp_radio_setconfiguration_80211(struct capwap_parsed_packet *packet
/* Parsing only IEEE 802.11 message element */
if (!IS_80211_MESSAGE_ELEMENTS(messageelement->id) &&
memcmp(&messageelement->id, &CAPWAP_ELEMENT_80211N_RADIO_CONF, sizeof(messageelement->id)) != 0)
!message_element_id_eq(messageelement->id, CAPWAP_ELEMENT_80211N_RADIO_CONF))
continue;
ASSERT(messageelements != NULL);
@ -255,7 +255,7 @@ static void wtp_radio_setconfiguration_80211(struct capwap_parsed_packet *packet
/* Parsing only IEEE 802.11 message element */
if (!IS_80211_MESSAGE_ELEMENTS(messageelement->id) &&
memcmp(&messageelement->id, &CAPWAP_ELEMENT_80211N_RADIO_CONF, sizeof(messageelement->id)) != 0)
!message_element_id_eq(messageelement->id, CAPWAP_ELEMENT_80211N_RADIO_CONF))
continue;
ASSERT(messageelements != NULL);
@ -652,6 +652,16 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons
}
}
/* source http://stackoverflow.com/a/16994674 */
static uint16_t reverse(register uint16_t x)
{
x = (((x & 0xaaaa) >> 1) | ((x & 0x5555) << 1));
x = (((x & 0xcccc) >> 2) | ((x & 0x3333) << 2));
x = (((x & 0xf0f0) >> 4) | ((x & 0x0f0f) << 4));
x = (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8));
return x;
}
/* */
uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
struct capwap_80211_assignbssid_element* bssid)
@ -700,11 +710,16 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
params.wlanid = addwlan->wlanid;
params.ssid = (const char*)addwlan->ssid;
params.ssid_hidden = addwlan->suppressssid;
params.capability = addwlan->capability;
params.capability = reverse(addwlan->capability);
params.qos = addwlan->qos;
params.authmode = addwlan->authmode;
params.macmode = addwlan->macmode;
params.tunnelmode = addwlan->tunnelmode;
params.keyindex = addwlan->keyindex;
params.keylength = addwlan->keylength;
params.key = addwlan->key;
params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE);
/* Start AP */
@ -725,8 +740,61 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet,
}
/* */
uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet) {
/* TODO */
uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet)
{
struct wtp_radio* radio;
struct wtp_radio_wlan* wlan;
struct wlan_updateap_params params;
struct capwap_80211_updatewlan_element* updatewlan;
ASSERT(packet != NULL);
/* Get message elements */
updatewlan = (struct capwap_80211_updatewlan_element*)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_UPDATE_WLAN);
if (!updatewlan) {
log_printf(LOG_DEBUG, "Update WLAN: no wlan");
return CAPWAP_RESULTCODE_FAILURE;
}
/* Get physical radio */
radio = wtp_radio_get_phy(updatewlan->radioid);
if (!radio) {
log_printf(LOG_DEBUG, "Update WLAN: no radio");
return CAPWAP_RESULTCODE_FAILURE;
}
/* Check if virtual interface is already exist */
wlan = wtp_radio_get_wlan(radio, updatewlan->wlanid);
if (!wlan || !wlan->wlanhandle) {
log_printf(LOG_DEBUG, "Update WLAN: invalid WLAN ID");
return CAPWAP_RESULTCODE_FAILURE;
}
if (!wlan->in_use) {
log_printf(LOG_DEBUG, "Update WLAN: vif does not exists");
return CAPWAP_RESULTCODE_FAILURE;
}
/* Wlan Update Configuration */
memset(&params, 0, sizeof(struct wlan_updateap_params));
params.radioid = updatewlan->radioid;
params.wlanid = updatewlan->wlanid;
params.capability = reverse(updatewlan->capability);
params.keyindex = updatewlan->keyindex;
params.keystatus = updatewlan->keystatus;
params.keylength = updatewlan->keylength;
params.key = updatewlan->key;
params.ie = (struct capwap_array *)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE);
/* Update AP */
if (wifi_wlan_updateap(wlan->wlanhandle, &params)) {
log_printf(LOG_DEBUG, "Update WLAN: update AP failed");
return CAPWAP_RESULTCODE_FAILURE;
}
return CAPWAP_RESULTCODE_SUCCESS;
}
@ -741,11 +809,14 @@ uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) {
struct capwap_addstation_element* addstation;
struct capwap_80211_station_element* station80211;
struct capwap_80211n_station_info_element *station80211n;
struct capwap_80211_stationkey_element *key;
struct capwap_array *ie;
struct wtp_radio* radio;
struct wtp_radio_wlan* wlan;
struct station_add_params stationparams;
struct ieee80211_ht_cap ht_cap;
int err;
uint32_t flags = 0;
int err, i;
/* Get message elements */
addstation = (struct capwap_addstation_element*)
@ -754,6 +825,10 @@ uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) {
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_STATION);
station80211n = (struct capwap_80211n_station_info_element *)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211N_STATION_INFO);
key = (struct capwap_80211_stationkey_element *)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_STATION_SESSION_KEY_PROFILE);
ie = (struct capwap_array *)
capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE);
if (!station80211 || (addstation->radioid != station80211->radioid)) {
log_printf(LOG_DEBUG, "add_station: error no station or wrong radio");
@ -818,7 +893,53 @@ uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) {
stationparams.max_inactivity = g_wtp.sta_max_inactivity;
}
err = wtp_kmod_add_station(addstation->radioid, station80211->address, station80211->wlanid);
if (key) {
if (memcmp(station80211->address, key->address,
MACADDRESS_EUI48_LENGTH) != 0) {
log_printf(LOG_DEBUG, "add_station: 802.11n Station Session Key MAC mismatch");
return CAPWAP_RESULTCODE_FAILURE;
}
log_printf(LOG_DEBUG, "add_station: key flags: %04x", key->flags);
if (key->flags & 0x8000)
flags |= STA_FLAG_AKM_ONLY;
stationparams.key = key;
}
if (ie) {
for (i = 0; i < ie->count; i++) {
struct ieee80211_ie *rsn;
uint8_t *data;
struct capwap_80211_ie_element *e =
*(struct capwap_80211_ie_element **)capwap_array_get_item_pointer(ie, i);
if (e->radioid != station80211->radioid ||
e->wlanid != station80211->wlanid ||
e->ielength < 2)
continue;
rsn = (struct ieee80211_ie *)e->ie;
if (rsn->id != IEEE80211_IE_RSN_INFORMATION)
continue;
data = (uint8_t *)(rsn + 1);
data += 2; // RSN Version
data += 4; // Group Chipher Suite
if (*(uint16_t *)data != 1) {
log_printf(LOG_DEBUG, "add_station: RSNE IE, wrong Pairwise Cipher Suite Count (%d)",
*(uint16_t *)data);
return CAPWAP_RESULTCODE_FAILURE;
}
data +=2; // Pairwise Cipher Suiter Length
stationparams.pairwise = ntohl(*(uint32_t *)data);
break;
}
}
err = wtp_kmod_add_station(addstation->radioid, station80211->address, station80211->wlanid, flags);
if (err < 0) {
log_printf(LOG_DEBUG, "add_station: CAPWAP add_station failed with: %d", err);
return CAPWAP_RESULTCODE_FAILURE;