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