2006-01-12 21:12:59 +01:00
/*
* This file contains the softmac ' s authentication logic .
*
2006-01-31 19:31:41 +01:00
* Copyright ( c ) 2005 , 2006 Johannes Berg < johannes @ sipsolutions . net >
* Joseph Jezak < josejx @ gentoo . org >
* Larry Finger < Larry . Finger @ lwfinger . net >
* Danny van Dyk < kugelfang @ gentoo . org >
* Michael Buesch < mbuesch @ freenet . de >
2006-01-12 21:12:59 +01:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* The full GNU General Public License is included in this distribution in the
* file called COPYING .
*/
2006-01-04 16:32:16 +01:00
# include "ieee80211softmac_priv.h"
2006-11-22 14:57:56 +00:00
static void ieee80211softmac_auth_queue ( struct work_struct * work ) ;
2006-01-04 16:32:16 +01:00
/* Queues an auth request to the desired AP */
int
2007-02-09 23:24:46 +09:00
ieee80211softmac_auth_req ( struct ieee80211softmac_device * mac ,
2006-01-04 16:32:16 +01:00
struct ieee80211softmac_network * net )
{
struct ieee80211softmac_auth_queue_item * auth ;
unsigned long flags ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac2 ) ;
2007-02-09 23:24:46 +09:00
2006-06-11 12:00:37 -04:00
if ( net - > authenticating | | net - > authenticated )
2006-01-04 16:32:16 +01:00
return 0 ;
2006-06-11 12:00:37 -04:00
net - > authenticating = 1 ;
2006-01-04 16:32:16 +01:00
/* Add the network if it's not already added */
ieee80211softmac_add_network ( mac , net ) ;
2007-10-03 17:59:30 -07:00
dprintk ( KERN_NOTICE PFX " Queueing Authentication Request to %s \n " , print_mac ( mac2 , net - > bssid ) ) ;
2006-01-04 16:32:16 +01:00
/* Queue the auth request */
auth = ( struct ieee80211softmac_auth_queue_item * )
kmalloc ( sizeof ( struct ieee80211softmac_auth_queue_item ) , GFP_KERNEL ) ;
if ( auth = = NULL )
return - ENOMEM ;
auth - > net = net ;
auth - > mac = mac ;
auth - > retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT ;
auth - > state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST ;
2006-11-22 14:57:56 +00:00
INIT_DELAYED_WORK ( & auth - > work , ieee80211softmac_auth_queue ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Lock (for list) */
spin_lock_irqsave ( & mac - > lock , flags ) ;
/* add to list */
list_add_tail ( & auth - > list , & mac - > auth_queue ) ;
2007-10-03 18:14:23 -07:00
queue_delayed_work ( mac - > wq , & auth - > work , 0 ) ;
2006-01-04 16:32:16 +01:00
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
return 0 ;
}
/* Sends an auth request to the desired AP and handles timeouts */
static void
2006-11-22 14:57:56 +00:00
ieee80211softmac_auth_queue ( struct work_struct * work )
2006-01-04 16:32:16 +01:00
{
struct ieee80211softmac_device * mac ;
struct ieee80211softmac_auth_queue_item * auth ;
struct ieee80211softmac_network * net ;
unsigned long flags ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac2 ) ;
2006-01-04 16:32:16 +01:00
2006-11-22 14:57:56 +00:00
auth = container_of ( work , struct ieee80211softmac_auth_queue_item ,
work . work ) ;
2006-01-04 16:32:16 +01:00
net = auth - > net ;
mac = auth - > mac ;
if ( auth - > retry > 0 ) {
/* Switch to correct channel for this network */
mac - > set_channel ( mac - > dev , net - > channel ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Lock and set flags */
spin_lock_irqsave ( & mac - > lock , flags ) ;
2006-04-30 22:09:07 +01:00
if ( unlikely ( ! mac - > running ) ) {
/* Prevent reschedule on workqueue flush */
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
return ;
}
2006-01-04 16:32:16 +01:00
net - > authenticated = 0 ;
/* add a timeout call so we eventually give up waiting for an auth reply */
2007-10-03 18:14:23 -07:00
queue_delayed_work ( mac - > wq , & auth - > work , IEEE80211SOFTMAC_AUTH_TIMEOUT ) ;
2006-01-04 16:32:16 +01:00
auth - > retry - - ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
if ( ieee80211softmac_send_mgt_frame ( mac , auth - > net , IEEE80211_STYPE_AUTH , auth - > state ) )
2007-10-03 17:59:30 -07:00
dprintk ( KERN_NOTICE PFX " Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout). \n " ,
print_mac ( mac2 , net - > bssid ) ) ;
2006-01-04 16:32:16 +01:00
else
2007-10-03 17:59:30 -07:00
dprintk ( KERN_NOTICE PFX " Sent Authentication Request to %s. \n " , print_mac ( mac2 , net - > bssid ) ) ;
2006-01-04 16:32:16 +01:00
return ;
}
2007-10-03 17:59:30 -07:00
printkl ( KERN_WARNING PFX " Authentication timed out with %s \n " , print_mac ( mac2 , net - > bssid ) ) ;
2006-01-04 16:32:16 +01:00
/* Remove this item from the queue */
spin_lock_irqsave ( & mac - > lock , flags ) ;
2006-06-01 15:34:26 +01:00
net - > authenticating = 0 ;
2006-01-04 16:32:16 +01:00
ieee80211softmac_call_events_locked ( mac , IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT , net ) ;
cancel_delayed_work ( & auth - > work ) ; /* just to make sure... */
list_del ( & auth - > list ) ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
/* Free it */
kfree ( auth ) ;
}
2006-07-11 23:16:34 +01:00
/* Sends a response to an auth challenge (for shared key auth). */
static void
2006-11-22 14:57:56 +00:00
ieee80211softmac_auth_challenge_response ( struct work_struct * work )
2006-07-11 23:16:34 +01:00
{
2006-11-22 14:57:56 +00:00
struct ieee80211softmac_auth_queue_item * aq =
container_of ( work , struct ieee80211softmac_auth_queue_item ,
work . work ) ;
2006-07-11 23:16:34 +01:00
/* Send our response */
ieee80211softmac_send_mgt_frame ( aq - > mac , aq - > net , IEEE80211_STYPE_AUTH , aq - > state ) ;
}
2006-01-04 16:32:16 +01:00
/* Handle the auth response from the AP
2007-02-09 23:24:46 +09:00
* This should be registered with ieee80211 as handle_auth
2006-01-04 16:32:16 +01:00
*/
2007-02-09 23:24:46 +09:00
int
2006-01-04 16:32:16 +01:00
ieee80211softmac_auth_resp ( struct net_device * dev , struct ieee80211_auth * auth )
2007-02-09 23:24:46 +09:00
{
2006-01-04 16:32:16 +01:00
struct list_head * list_ptr ;
struct ieee80211softmac_device * mac = ieee80211_priv ( dev ) ;
struct ieee80211softmac_auth_queue_item * aq = NULL ;
struct ieee80211softmac_network * net = NULL ;
unsigned long flags ;
u8 * data ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac2 ) ;
2007-02-09 23:24:46 +09:00
2006-04-30 22:09:07 +01:00
if ( unlikely ( ! mac - > running ) )
return - ENODEV ;
2006-01-04 16:32:16 +01:00
/* Find correct auth queue item */
spin_lock_irqsave ( & mac - > lock , flags ) ;
list_for_each ( list_ptr , & mac - > auth_queue ) {
aq = list_entry ( list_ptr , struct ieee80211softmac_auth_queue_item , list ) ;
net = aq - > net ;
if ( ! memcmp ( net - > bssid , auth - > header . addr2 , ETH_ALEN ) )
break ;
else
aq = NULL ;
}
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Make sure that we've got an auth queue item for this request */
if ( aq = = NULL )
{
2007-10-03 17:59:30 -07:00
dprintkl ( KERN_DEBUG PFX " Authentication response received from %s but no queue item exists. \n " , print_mac ( mac2 , auth - > header . addr2 ) ) ;
2006-01-04 16:32:16 +01:00
/* Error #? */
return - 1 ;
2007-02-09 23:24:46 +09:00
}
2006-01-04 16:32:16 +01:00
/* Check for out of order authentication */
if ( ! net - > authenticating )
{
2007-10-03 17:59:30 -07:00
dprintkl ( KERN_DEBUG PFX " Authentication response received from %s but did not request authentication. \n " , print_mac ( mac2 , auth - > header . addr2 ) ) ;
2006-01-04 16:32:16 +01:00
return - 1 ;
}
/* Parse the auth packet */
switch ( auth - > algorithm ) {
case WLAN_AUTH_OPEN :
/* Check the status code of the response */
switch ( auth - > status ) {
case WLAN_STATUS_SUCCESS :
/* Update the status to Authenticated */
spin_lock_irqsave ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
net - > authenticating = 0 ;
2006-01-04 16:32:16 +01:00
net - > authenticated = 1 ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Send event */
2007-10-03 17:59:30 -07:00
printkl ( KERN_NOTICE PFX " Open Authentication completed with %s \n " , print_mac ( mac2 , net - > bssid ) ) ;
2006-01-04 16:32:16 +01:00
ieee80211softmac_call_events ( mac , IEEE80211SOFTMAC_EVENT_AUTHENTICATED , net ) ;
break ;
default :
/* Lock and reset flags */
spin_lock_irqsave ( & mac - > lock , flags ) ;
net - > authenticated = 0 ;
net - > authenticating = 0 ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
2007-10-03 17:59:30 -07:00
printkl ( KERN_NOTICE PFX " Open Authentication with %s failed, error code: %i \n " ,
print_mac ( mac2 , net - > bssid ) , le16_to_cpup ( & auth - > status ) ) ;
2006-01-04 16:32:16 +01:00
/* Count the error? */
break ;
}
goto free_aq ;
break ;
case WLAN_AUTH_SHARED_KEY :
/* Figure out where we are in the process */
switch ( auth - > transaction ) {
case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE :
/* Check to make sure we have a challenge IE */
data = ( u8 * ) auth - > info_element ;
2006-07-11 23:16:34 +01:00
if ( * data + + ! = MFIE_TYPE_CHALLENGE ) {
2006-01-04 16:32:16 +01:00
printkl ( KERN_NOTICE PFX " Shared Key Authentication failed due to a missing challenge. \n " ) ;
2007-02-09 23:24:46 +09:00
break ;
2006-01-04 16:32:16 +01:00
}
/* Save the challenge */
spin_lock_irqsave ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
net - > challenge_len = * data + + ;
2006-07-11 23:16:34 +01:00
if ( net - > challenge_len > WLAN_AUTH_CHALLENGE_LEN )
2006-01-04 16:32:16 +01:00
net - > challenge_len = WLAN_AUTH_CHALLENGE_LEN ;
2006-11-21 01:26:49 -02:00
kfree ( net - > challenge ) ;
net - > challenge = kmemdup ( data , net - > challenge_len ,
GFP_ATOMIC ) ;
if ( net - > challenge = = NULL ) {
printkl ( KERN_NOTICE PFX " Shared Key "
" Authentication failed due to "
" memory shortage. \n " ) ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
break ;
}
2007-02-09 23:24:46 +09:00
aq - > state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE ;
2006-01-04 16:32:16 +01:00
2006-07-11 23:16:34 +01:00
/* We reuse the work struct from the auth request here.
* It is safe to do so as each one is per - request , and
* at this point ( dealing with authentication response )
* we have obviously already sent the initial auth
* request . */
cancel_delayed_work ( & aq - > work ) ;
2006-11-22 14:57:56 +00:00
INIT_DELAYED_WORK ( & aq - > work , & ieee80211softmac_auth_challenge_response ) ;
2007-10-03 18:14:23 -07:00
queue_delayed_work ( mac - > wq , & aq - > work , 0 ) ;
2006-07-11 23:16:34 +01:00
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2006-06-01 15:34:26 +01:00
return 0 ;
2006-01-04 16:32:16 +01:00
case IEEE80211SOFTMAC_AUTH_SHARED_PASS :
2006-06-01 15:34:26 +01:00
kfree ( net - > challenge ) ;
net - > challenge = NULL ;
net - > challenge_len = 0 ;
2006-01-04 16:32:16 +01:00
/* Check the status code of the response */
switch ( auth - > status ) {
case WLAN_STATUS_SUCCESS :
2007-02-09 23:24:46 +09:00
/* Update the status to Authenticated */
2006-01-04 16:32:16 +01:00
spin_lock_irqsave ( & mac - > lock , flags ) ;
net - > authenticating = 0 ;
net - > authenticated = 1 ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2007-10-03 17:59:30 -07:00
printkl ( KERN_NOTICE PFX " Shared Key Authentication completed with %s \n " ,
print_mac ( mac2 , net - > bssid ) ) ;
2006-06-01 15:34:26 +01:00
ieee80211softmac_call_events ( mac , IEEE80211SOFTMAC_EVENT_AUTHENTICATED , net ) ;
2006-01-04 16:32:16 +01:00
break ;
default :
2007-10-03 17:59:30 -07:00
printkl ( KERN_NOTICE PFX " Shared Key Authentication with %s failed, error code: %i \n " ,
print_mac ( mac2 , net - > bssid ) , le16_to_cpup ( & auth - > status ) ) ;
2006-01-04 16:32:16 +01:00
/* Lock and reset flags */
spin_lock_irqsave ( & mac - > lock , flags ) ;
2007-02-09 23:24:46 +09:00
net - > authenticating = 0 ;
net - > authenticated = 0 ;
2006-01-04 16:32:16 +01:00
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
/* Count the error? */
break ;
}
goto free_aq ;
break ;
default :
printkl ( KERN_WARNING PFX " Unhandled Authentication Step: %i \n " , auth - > transaction ) ;
break ;
}
goto free_aq ;
break ;
default :
2007-02-09 23:24:46 +09:00
/* ERROR */
2006-01-04 16:32:16 +01:00
goto free_aq ;
break ;
}
return 0 ;
free_aq :
/* Cancel the timeout */
spin_lock_irqsave ( & mac - > lock , flags ) ;
cancel_delayed_work ( & aq - > work ) ;
/* Remove this item from the queue */
list_del ( & aq - > list ) ;
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
/* Free it */
kfree ( aq ) ;
return 0 ;
}
/*
* Handle deauthorization
*/
2006-01-04 21:06:28 +01:00
static void
2006-01-04 16:32:16 +01:00
ieee80211softmac_deauth_from_net ( struct ieee80211softmac_device * mac ,
struct ieee80211softmac_network * net )
{
struct ieee80211softmac_auth_queue_item * aq = NULL ;
struct list_head * list_ptr ;
unsigned long flags ;
2006-05-01 22:23:27 +01:00
/* deauthentication implies disassociation */
ieee80211softmac_disassoc ( mac ) ;
2006-01-04 16:32:16 +01:00
/* Lock and reset status flags */
spin_lock_irqsave ( & mac - > lock , flags ) ;
net - > authenticating = 0 ;
net - > authenticated = 0 ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Find correct auth queue item, if it exists */
list_for_each ( list_ptr , & mac - > auth_queue ) {
aq = list_entry ( list_ptr , struct ieee80211softmac_auth_queue_item , list ) ;
if ( ! memcmp ( net - > bssid , aq - > net - > bssid , ETH_ALEN ) )
break ;
else
aq = NULL ;
}
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Cancel pending work */
if ( aq ! = NULL )
/* Not entirely safe? What about running work? */
cancel_delayed_work ( & aq - > work ) ;
/* Free our network ref */
ieee80211softmac_del_network_locked ( mac , net ) ;
if ( net - > challenge ! = NULL )
kfree ( net - > challenge ) ;
kfree ( net ) ;
2007-02-09 23:24:46 +09:00
2006-01-06 18:11:23 +01:00
/* can't transmit data right now... */
netif_carrier_off ( mac - > dev ) ;
2006-01-04 16:32:16 +01:00
spin_unlock_irqrestore ( & mac - > lock , flags ) ;
2006-12-03 16:32:00 +01:00
ieee80211softmac_try_reassoc ( mac ) ;
2006-01-04 16:32:16 +01:00
}
2007-02-09 23:24:46 +09:00
/*
2006-01-04 16:32:16 +01:00
* Sends a deauth request to the desired AP
*/
2007-02-09 23:24:46 +09:00
int
ieee80211softmac_deauth_req ( struct ieee80211softmac_device * mac ,
2006-01-04 16:32:16 +01:00
struct ieee80211softmac_network * net , int reason )
{
int ret ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Make sure the network is authenticated */
if ( ! net - > authenticated )
{
2006-11-04 13:29:50 -06:00
dprintkl ( KERN_DEBUG PFX " Can't send deauthentication packet, network is not authenticated. \n " ) ;
2006-01-04 16:32:16 +01:00
/* Error okay? */
return - EPERM ;
}
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/* Send the de-auth packet */
if ( ( ret = ieee80211softmac_send_mgt_frame ( mac , net , IEEE80211_STYPE_DEAUTH , reason ) ) )
return ret ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
ieee80211softmac_deauth_from_net ( mac , net ) ;
return 0 ;
}
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
/*
* This should be registered with ieee80211 as handle_deauth
*/
2007-02-09 23:24:46 +09:00
int
2006-01-31 19:48:06 +01:00
ieee80211softmac_deauth_resp ( struct net_device * dev , struct ieee80211_deauth * deauth )
2006-01-04 16:32:16 +01:00
{
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
struct ieee80211softmac_network * net = NULL ;
struct ieee80211softmac_device * mac = ieee80211_priv ( dev ) ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac2 ) ;
2007-02-09 23:24:46 +09:00
2006-04-30 22:09:07 +01:00
if ( unlikely ( ! mac - > running ) )
return - ENODEV ;
2006-01-31 19:48:06 +01:00
if ( ! deauth ) {
2006-01-04 16:32:16 +01:00
dprintk ( " deauth without deauth packet. eek! \n " ) ;
return 0 ;
}
2006-01-31 19:48:06 +01:00
net = ieee80211softmac_get_network_by_bssid ( mac , deauth - > header . addr2 ) ;
2007-02-09 23:24:46 +09:00
2006-01-04 16:32:16 +01:00
if ( net = = NULL ) {
2007-10-03 17:59:30 -07:00
dprintkl ( KERN_DEBUG PFX " Received deauthentication packet from %s, but that network is unknown. \n " ,
print_mac ( mac2 , deauth - > header . addr2 ) ) ;
2006-01-04 16:32:16 +01:00
return 0 ;
}
/* Make sure the network is authenticated */
if ( ! net - > authenticated )
{
2006-11-04 13:29:50 -06:00
dprintkl ( KERN_DEBUG PFX " Can't perform deauthentication, network is not authenticated. \n " ) ;
2006-01-04 16:32:16 +01:00
/* Error okay? */
return - EPERM ;
}
ieee80211softmac_deauth_from_net ( mac , net ) ;
2006-04-30 19:49:30 +01:00
/* let's try to re-associate */
2007-10-03 18:14:23 -07:00
queue_delayed_work ( mac - > wq , & mac - > associnfo . work , 0 ) ;
2006-01-04 16:32:16 +01:00
return 0 ;
}