2011-06-10 01:50:40 +04:00
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation ;
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS .
IN NO EVENT SHALL THE COPYRIGHT HOLDER ( S ) AND AUTHOR ( S ) BE LIABLE FOR ANY
CLAIM , OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES , OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED .
*/
2012-05-23 11:04:22 +04:00
# include <linux/crypto.h>
# include <linux/scatterlist.h>
# include <crypto/b128ops.h>
2011-06-10 01:50:40 +04:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include <net/bluetooth/l2cap.h>
2011-12-22 04:12:12 +04:00
# include <net/bluetooth/mgmt.h>
2013-10-11 01:54:16 +04:00
# include "smp.h"
2011-06-10 01:50:44 +04:00
2012-03-02 02:32:37 +04:00
# define SMP_TIMEOUT msecs_to_jiffies(30000)
2011-06-14 20:37:41 +04:00
2012-10-11 18:26:06 +04:00
# define AUTH_REQ_MASK 0x07
2014-03-18 14:58:23 +04:00
static inline void swap128 ( const u8 src [ 16 ] , u8 dst [ 16 ] )
2011-06-10 01:50:44 +04:00
{
int i ;
for ( i = 0 ; i < 16 ; i + + )
dst [ 15 - i ] = src [ i ] ;
}
2014-03-18 14:58:23 +04:00
static inline void swap56 ( const u8 src [ 7 ] , u8 dst [ 7 ] )
2011-06-10 01:50:44 +04:00
{
int i ;
for ( i = 0 ; i < 7 ; i + + )
dst [ 6 - i ] = src [ i ] ;
}
static int smp_e ( struct crypto_blkcipher * tfm , const u8 * k , u8 * r )
{
struct blkcipher_desc desc ;
struct scatterlist sg ;
2014-03-18 14:58:24 +04:00
uint8_t tmp [ 16 ] , data [ 16 ] ;
2013-12-02 12:49:04 +04:00
int err ;
2011-06-10 01:50:44 +04:00
if ( tfm = = NULL ) {
BT_ERR ( " tfm %p " , tfm ) ;
return - EINVAL ;
}
desc . tfm = tfm ;
desc . flags = 0 ;
2014-03-18 14:58:24 +04:00
/* The most significant octet of key corresponds to k[0] */
swap128 ( k , tmp ) ;
err = crypto_blkcipher_setkey ( tfm , tmp , 16 ) ;
2011-06-10 01:50:44 +04:00
if ( err ) {
BT_ERR ( " cipher setkey failed: %d " , err ) ;
return err ;
}
2014-03-18 14:58:24 +04:00
/* Most significant octet of plaintextData corresponds to data[0] */
swap128 ( r , data ) ;
sg_init_one ( & sg , data , 16 ) ;
2011-06-10 01:50:44 +04:00
err = crypto_blkcipher_encrypt ( & desc , & sg , & sg , 16 ) ;
if ( err )
BT_ERR ( " Encrypt data error %d " , err ) ;
2014-03-18 14:58:24 +04:00
/* Most significant octet of encryptedData corresponds to data[0] */
swap128 ( data , r ) ;
2011-06-10 01:50:44 +04:00
return err ;
}
2014-02-18 12:19:31 +04:00
static int smp_ah ( struct crypto_blkcipher * tfm , u8 irk [ 16 ] , u8 r [ 3 ] , u8 res [ 3 ] )
{
2014-03-18 14:58:24 +04:00
u8 _res [ 16 ] ;
2014-02-18 12:19:31 +04:00
int err ;
/* r' = padding || r */
2014-03-18 14:58:24 +04:00
memcpy ( _res , r , 3 ) ;
memset ( _res + 3 , 0 , 13 ) ;
2014-02-18 12:19:31 +04:00
2014-03-18 14:58:24 +04:00
err = smp_e ( tfm , irk , _res ) ;
2014-02-18 12:19:31 +04:00
if ( err ) {
BT_ERR ( " Encrypt error " ) ;
return err ;
}
/* The output of the random address function ah is:
* ah ( h , r ) = e ( k , r ' ) mod 2 ^ 24
* The output of the security function e is then truncated to 24 bits
* by taking the least significant 24 bits of the output of e as the
* result of ah .
*/
2014-03-18 14:58:24 +04:00
memcpy ( res , _res , 3 ) ;
2014-02-18 12:19:31 +04:00
return 0 ;
}
bool smp_irk_matches ( struct crypto_blkcipher * tfm , u8 irk [ 16 ] ,
bdaddr_t * bdaddr )
{
u8 hash [ 3 ] ;
int err ;
BT_DBG ( " RPA %pMR IRK %*phN " , bdaddr , 16 , irk ) ;
err = smp_ah ( tfm , irk , & bdaddr - > b [ 3 ] , hash ) ;
if ( err )
return false ;
return ! memcmp ( bdaddr - > b , hash , 3 ) ;
}
2014-02-23 21:42:19 +04:00
int smp_generate_rpa ( struct crypto_blkcipher * tfm , u8 irk [ 16 ] , bdaddr_t * rpa )
{
int err ;
get_random_bytes ( & rpa - > b [ 3 ] , 3 ) ;
rpa - > b [ 5 ] & = 0x3f ; /* Clear two most significant bits */
rpa - > b [ 5 ] | = 0x40 ; /* Set second most significant bit */
err = smp_ah ( tfm , irk , & rpa - > b [ 3 ] , rpa - > b ) ;
if ( err < 0 )
return err ;
BT_DBG ( " RPA %pMR " , rpa ) ;
return 0 ;
}
2011-06-10 01:50:44 +04:00
static int smp_c1 ( struct crypto_blkcipher * tfm , u8 k [ 16 ] , u8 r [ 16 ] ,
2013-10-13 16:43:25 +04:00
u8 preq [ 7 ] , u8 pres [ 7 ] , u8 _iat , bdaddr_t * ia ,
u8 _rat , bdaddr_t * ra , u8 res [ 16 ] )
2011-06-10 01:50:44 +04:00
{
u8 p1 [ 16 ] , p2 [ 16 ] ;
int err ;
memset ( p1 , 0 , 16 ) ;
/* p1 = pres || preq || _rat || _iat */
2014-03-18 14:58:24 +04:00
p1 [ 0 ] = _iat ;
p1 [ 1 ] = _rat ;
memcpy ( p1 + 2 , preq , 7 ) ;
memcpy ( p1 + 9 , pres , 7 ) ;
2011-06-10 01:50:44 +04:00
/* p2 = padding || ia || ra */
2014-03-18 14:58:24 +04:00
memcpy ( p2 , ra , 6 ) ;
memcpy ( p2 + 6 , ia , 6 ) ;
memset ( p2 + 12 , 0 , 4 ) ;
2011-06-10 01:50:44 +04:00
/* res = r XOR p1 */
u128_xor ( ( u128 * ) res , ( u128 * ) r , ( u128 * ) p1 ) ;
/* res = e(k, res) */
err = smp_e ( tfm , k , res ) ;
if ( err ) {
BT_ERR ( " Encrypt data error " ) ;
return err ;
}
/* res = res XOR p2 */
u128_xor ( ( u128 * ) res , ( u128 * ) res , ( u128 * ) p2 ) ;
/* res = e(k, res) */
err = smp_e ( tfm , k , res ) ;
if ( err )
BT_ERR ( " Encrypt data error " ) ;
return err ;
}
2013-10-13 16:43:25 +04:00
static int smp_s1 ( struct crypto_blkcipher * tfm , u8 k [ 16 ] , u8 r1 [ 16 ] ,
u8 r2 [ 16 ] , u8 _r [ 16 ] )
2011-06-10 01:50:44 +04:00
{
int err ;
/* Just least significant octets from r1 and r2 are considered */
2014-03-18 14:58:24 +04:00
memcpy ( _r , r2 , 8 ) ;
memcpy ( _r + 8 , r1 , 8 ) ;
2011-06-10 01:50:44 +04:00
err = smp_e ( tfm , k , _r ) ;
if ( err )
BT_ERR ( " Encrypt data error " ) ;
return err ;
}
2011-06-10 01:50:40 +04:00
static struct sk_buff * smp_build_cmd ( struct l2cap_conn * conn , u8 code ,
2013-10-13 16:43:25 +04:00
u16 dlen , void * data )
2011-06-10 01:50:40 +04:00
{
struct sk_buff * skb ;
struct l2cap_hdr * lh ;
int len ;
len = L2CAP_HDR_SIZE + sizeof ( code ) + dlen ;
if ( len > conn - > mtu )
return NULL ;
skb = bt_skb_alloc ( len , GFP_ATOMIC ) ;
if ( ! skb )
return NULL ;
lh = ( struct l2cap_hdr * ) skb_put ( skb , L2CAP_HDR_SIZE ) ;
lh - > len = cpu_to_le16 ( sizeof ( code ) + dlen ) ;
2014-03-12 21:52:35 +04:00
lh - > cid = cpu_to_le16 ( L2CAP_CID_SMP ) ;
2011-06-10 01:50:40 +04:00
memcpy ( skb_put ( skb , sizeof ( code ) ) , & code , sizeof ( code ) ) ;
memcpy ( skb_put ( skb , dlen ) , data , dlen ) ;
return skb ;
}
static void smp_send_cmd ( struct l2cap_conn * conn , u8 code , u16 len , void * data )
{
struct sk_buff * skb = smp_build_cmd ( conn , code , len , data ) ;
BT_DBG ( " code 0x%2.2x " , code ) ;
if ( ! skb )
return ;
2011-11-02 17:52:01 +04:00
skb - > priority = HCI_PRIO_MAX ;
hci_send_acl ( conn - > hchan , skb , 0 ) ;
2011-08-20 04:06:50 +04:00
2011-12-20 16:57:27 +04:00
cancel_delayed_work_sync ( & conn - > security_timer ) ;
2012-03-02 02:32:37 +04:00
schedule_delayed_work ( & conn - > security_timer , SMP_TIMEOUT ) ;
2011-06-10 01:50:40 +04:00
}
2011-12-22 04:12:12 +04:00
static __u8 authreq_to_seclevel ( __u8 authreq )
{
if ( authreq & SMP_AUTH_MITM )
return BT_SECURITY_HIGH ;
else
return BT_SECURITY_MEDIUM ;
}
static __u8 seclevel_to_authreq ( __u8 sec_level )
{
switch ( sec_level ) {
case BT_SECURITY_HIGH :
return SMP_AUTH_MITM | SMP_AUTH_BONDING ;
case BT_SECURITY_MEDIUM :
return SMP_AUTH_BONDING ;
default :
return SMP_AUTH_NONE ;
}
}
2011-06-10 01:50:52 +04:00
static void build_pairing_cmd ( struct l2cap_conn * conn ,
2013-10-13 16:43:25 +04:00
struct smp_cmd_pairing * req ,
struct smp_cmd_pairing * rsp , __u8 authreq )
2011-06-10 01:50:52 +04:00
{
2014-02-18 12:19:36 +04:00
struct smp_chan * smp = conn - > smp_chan ;
struct hci_conn * hcon = conn - > hcon ;
struct hci_dev * hdev = hcon - > hdev ;
u8 local_dist = 0 , remote_dist = 0 ;
2011-07-08 01:59:38 +04:00
2012-01-09 01:11:15 +04:00
if ( test_bit ( HCI_PAIRABLE , & conn - > hcon - > hdev - > dev_flags ) ) {
2014-03-09 23:19:17 +04:00
local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN ;
remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN ;
2011-07-08 01:59:38 +04:00
authreq | = SMP_AUTH_BONDING ;
2011-12-22 04:12:12 +04:00
} else {
authreq & = ~ SMP_AUTH_BONDING ;
2011-07-08 01:59:38 +04:00
}
2014-02-18 12:19:36 +04:00
if ( test_bit ( HCI_RPA_RESOLVING , & hdev - > dev_flags ) )
remote_dist | = SMP_DIST_ID_KEY ;
2014-02-22 21:06:32 +04:00
if ( test_bit ( HCI_PRIVACY , & hdev - > dev_flags ) )
local_dist | = SMP_DIST_ID_KEY ;
2011-07-08 01:59:38 +04:00
if ( rsp = = NULL ) {
req - > io_capability = conn - > hcon - > io_capability ;
req - > oob_flag = SMP_OOB_NOT_PRESENT ;
req - > max_key_size = SMP_MAX_ENC_KEY_SIZE ;
2014-02-18 12:19:36 +04:00
req - > init_key_dist = local_dist ;
req - > resp_key_dist = remote_dist ;
2012-10-11 18:26:06 +04:00
req - > auth_req = ( authreq & AUTH_REQ_MASK ) ;
2014-02-18 12:19:36 +04:00
smp - > remote_key_dist = remote_dist ;
2011-07-08 01:59:38 +04:00
return ;
}
rsp - > io_capability = conn - > hcon - > io_capability ;
rsp - > oob_flag = SMP_OOB_NOT_PRESENT ;
rsp - > max_key_size = SMP_MAX_ENC_KEY_SIZE ;
2014-02-18 12:19:36 +04:00
rsp - > init_key_dist = req - > init_key_dist & remote_dist ;
rsp - > resp_key_dist = req - > resp_key_dist & local_dist ;
2012-10-11 18:26:06 +04:00
rsp - > auth_req = ( authreq & AUTH_REQ_MASK ) ;
2014-02-18 12:19:36 +04:00
smp - > remote_key_dist = rsp - > init_key_dist ;
2011-06-10 01:50:52 +04:00
}
2011-06-14 20:37:42 +04:00
static u8 check_enc_key_size ( struct l2cap_conn * conn , __u8 max_key_size )
{
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2011-06-14 20:37:42 +04:00
if ( ( max_key_size > SMP_MAX_ENC_KEY_SIZE ) | |
2013-10-13 16:43:25 +04:00
( max_key_size < SMP_MIN_ENC_KEY_SIZE ) )
2011-06-14 20:37:42 +04:00
return SMP_ENC_KEY_SIZE ;
2012-01-31 02:29:12 +04:00
smp - > enc_key_size = max_key_size ;
2011-06-14 20:37:42 +04:00
return 0 ;
}
2013-11-06 13:24:57 +04:00
static void smp_failure ( struct l2cap_conn * conn , u8 reason )
2011-11-23 20:28:36 +04:00
{
2012-02-09 18:07:29 +04:00
struct hci_conn * hcon = conn - > hcon ;
2013-11-06 13:24:57 +04:00
if ( reason )
2011-11-23 20:28:36 +04:00
smp_send_cmd ( conn , SMP_CMD_PAIRING_FAIL , sizeof ( reason ) ,
2013-10-13 16:43:25 +04:00
& reason ) ;
2011-11-23 20:28:36 +04:00
2013-10-13 13:23:39 +04:00
clear_bit ( HCI_CONN_ENCRYPT_PEND , & hcon - > flags ) ;
mgmt_auth_failed ( hcon - > hdev , & hcon - > dst , hcon - > type , hcon - > dst_type ,
HCI_ERROR_AUTH_FAILURE ) ;
2012-02-02 01:27:56 +04:00
2012-08-02 03:34:15 +04:00
cancel_delayed_work_sync ( & conn - > security_timer ) ;
2013-10-13 13:23:39 +04:00
if ( test_and_clear_bit ( HCI_CONN_LE_SMP_PEND , & hcon - > flags ) )
2012-02-02 01:27:56 +04:00
smp_chan_destroy ( conn ) ;
2011-11-23 20:28:36 +04:00
}
2011-12-22 04:12:12 +04:00
# define JUST_WORKS 0x00
# define JUST_CFM 0x01
# define REQ_PASSKEY 0x02
# define CFM_PASSKEY 0x03
# define REQ_OOB 0x04
# define OVERLAP 0xFF
static const u8 gen_method [ 5 ] [ 5 ] = {
{ JUST_WORKS , JUST_CFM , REQ_PASSKEY , JUST_WORKS , REQ_PASSKEY } ,
{ JUST_WORKS , JUST_CFM , REQ_PASSKEY , JUST_WORKS , REQ_PASSKEY } ,
{ CFM_PASSKEY , CFM_PASSKEY , REQ_PASSKEY , JUST_WORKS , CFM_PASSKEY } ,
{ JUST_WORKS , JUST_CFM , JUST_WORKS , JUST_WORKS , JUST_CFM } ,
{ CFM_PASSKEY , CFM_PASSKEY , REQ_PASSKEY , JUST_WORKS , OVERLAP } ,
} ;
static int tk_request ( struct l2cap_conn * conn , u8 remote_oob , u8 auth ,
u8 local_io , u8 remote_io )
{
struct hci_conn * hcon = conn - > hcon ;
struct smp_chan * smp = conn - > smp_chan ;
u8 method ;
u32 passkey = 0 ;
int ret = 0 ;
/* Initialize key for JUST WORKS */
memset ( smp - > tk , 0 , sizeof ( smp - > tk ) ) ;
clear_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) ;
BT_DBG ( " tk_request: auth:%d lcl:%d rem:%d " , auth , local_io , remote_io ) ;
/* If neither side wants MITM, use JUST WORKS */
/* If either side has unknown io_caps, use JUST WORKS */
/* Otherwise, look up method from the table */
if ( ! ( auth & SMP_AUTH_MITM ) | |
2013-10-13 16:43:25 +04:00
local_io > SMP_IO_KEYBOARD_DISPLAY | |
remote_io > SMP_IO_KEYBOARD_DISPLAY )
2011-12-22 04:12:12 +04:00
method = JUST_WORKS ;
else
2012-03-05 22:07:08 +04:00
method = gen_method [ remote_io ] [ local_io ] ;
2011-12-22 04:12:12 +04:00
/* If not bonding, don't ask user to confirm a Zero TK */
if ( ! ( auth & SMP_AUTH_BONDING ) & & method = = JUST_CFM )
method = JUST_WORKS ;
/* If Just Works, Continue with Zero TK */
if ( method = = JUST_WORKS ) {
set_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) ;
return 0 ;
}
/* Not Just Works/Confirm results in MITM Authentication */
if ( method ! = JUST_CFM )
set_bit ( SMP_FLAG_MITM_AUTH , & smp - > smp_flags ) ;
/* If both devices have Keyoard-Display I/O, the master
* Confirms and the slave Enters the passkey .
*/
if ( method = = OVERLAP ) {
if ( hcon - > link_mode & HCI_LM_MASTER )
method = CFM_PASSKEY ;
else
method = REQ_PASSKEY ;
}
2014-03-19 16:14:53 +04:00
/* Generate random passkey. */
2011-12-22 04:12:12 +04:00
if ( method = = CFM_PASSKEY ) {
2014-03-18 14:58:24 +04:00
memset ( smp - > tk , 0 , sizeof ( smp - > tk ) ) ;
2011-12-22 04:12:12 +04:00
get_random_bytes ( & passkey , sizeof ( passkey ) ) ;
passkey % = 1000000 ;
2014-03-18 14:58:24 +04:00
put_unaligned_le32 ( passkey , smp - > tk ) ;
2011-12-22 04:12:12 +04:00
BT_DBG ( " PassKey: %d " , passkey ) ;
2014-03-19 16:14:53 +04:00
set_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) ;
2011-12-22 04:12:12 +04:00
}
hci_dev_lock ( hcon - > hdev ) ;
if ( method = = REQ_PASSKEY )
2013-10-13 13:23:39 +04:00
ret = mgmt_user_passkey_request ( hcon - > hdev , & hcon - > dst ,
2012-02-09 17:26:12 +04:00
hcon - > type , hcon - > dst_type ) ;
2011-12-22 04:12:12 +04:00
else
2014-03-19 16:14:53 +04:00
ret = mgmt_user_passkey_notify ( hcon - > hdev , & hcon - > dst ,
2012-02-09 17:26:12 +04:00
hcon - > type , hcon - > dst_type ,
2014-03-20 10:18:14 +04:00
passkey , 0 ) ;
2011-12-22 04:12:12 +04:00
hci_dev_unlock ( hcon - > hdev ) ;
return ret ;
}
2011-09-05 21:31:31 +04:00
static void confirm_work ( struct work_struct * work )
{
struct smp_chan * smp = container_of ( work , struct smp_chan , confirm ) ;
struct l2cap_conn * conn = smp - > conn ;
2014-02-18 23:41:31 +04:00
struct hci_dev * hdev = conn - > hcon - > hdev ;
struct crypto_blkcipher * tfm = hdev - > tfm_aes ;
2011-09-05 21:31:31 +04:00
struct smp_cmd_pairing_confirm cp ;
int ret ;
2014-03-18 14:58:24 +04:00
u8 reason ;
2011-09-05 21:31:31 +04:00
BT_DBG ( " conn %p " , conn ) ;
2014-02-18 23:41:31 +04:00
/* Prevent mutual access to hdev->tfm_aes */
hci_dev_lock ( hdev ) ;
2011-09-05 21:31:31 +04:00
2014-02-28 14:54:17 +04:00
ret = smp_c1 ( tfm , smp - > tk , smp - > prnd , smp - > preq , smp - > prsp ,
conn - > hcon - > init_addr_type , & conn - > hcon - > init_addr ,
2014-03-18 14:58:24 +04:00
conn - > hcon - > resp_addr_type , & conn - > hcon - > resp_addr ,
cp . confirm_val ) ;
2014-02-18 23:41:31 +04:00
hci_dev_unlock ( hdev ) ;
2011-09-05 21:31:31 +04:00
if ( ret ) {
reason = SMP_UNSPECIFIED ;
goto error ;
}
2011-12-22 04:12:12 +04:00
clear_bit ( SMP_FLAG_CFM_PENDING , & smp - > smp_flags ) ;
2011-09-05 21:31:31 +04:00
smp_send_cmd ( smp - > conn , SMP_CMD_PAIRING_CONFIRM , sizeof ( cp ) , & cp ) ;
return ;
error :
2013-11-06 13:24:57 +04:00
smp_failure ( conn , reason ) ;
2011-09-05 21:31:31 +04:00
}
static void random_work ( struct work_struct * work )
{
struct smp_chan * smp = container_of ( work , struct smp_chan , random ) ;
struct l2cap_conn * conn = smp - > conn ;
struct hci_conn * hcon = conn - > hcon ;
2014-02-18 23:41:31 +04:00
struct hci_dev * hdev = hcon - > hdev ;
struct crypto_blkcipher * tfm = hdev - > tfm_aes ;
2014-03-18 14:58:24 +04:00
u8 reason , confirm [ 16 ] ;
2011-09-05 21:31:31 +04:00
int ret ;
if ( IS_ERR_OR_NULL ( tfm ) ) {
reason = SMP_UNSPECIFIED ;
goto error ;
}
BT_DBG ( " conn %p %s " , conn , conn - > hcon - > out ? " master " : " slave " ) ;
2014-02-18 23:41:31 +04:00
/* Prevent mutual access to hdev->tfm_aes */
hci_dev_lock ( hdev ) ;
2014-02-28 14:54:17 +04:00
ret = smp_c1 ( tfm , smp - > tk , smp - > rrnd , smp - > preq , smp - > prsp ,
hcon - > init_addr_type , & hcon - > init_addr ,
2014-03-18 14:58:24 +04:00
hcon - > resp_addr_type , & hcon - > resp_addr , confirm ) ;
2014-02-18 23:41:31 +04:00
hci_dev_unlock ( hdev ) ;
2011-09-05 21:31:31 +04:00
if ( ret ) {
reason = SMP_UNSPECIFIED ;
goto error ;
}
if ( memcmp ( smp - > pcnf , confirm , sizeof ( smp - > pcnf ) ) ! = 0 ) {
BT_ERR ( " Pairing failed (confirmation values mismatch) " ) ;
reason = SMP_CONFIRM_FAILED ;
goto error ;
}
if ( hcon - > out ) {
2014-02-28 04:00:28 +04:00
u8 stk [ 16 ] ;
__le64 rand = 0 ;
__le16 ediv = 0 ;
2011-09-05 21:31:31 +04:00
2014-03-18 14:58:24 +04:00
smp_s1 ( tfm , smp - > tk , smp - > rrnd , smp - > prnd , stk ) ;
2011-09-05 21:31:31 +04:00
2012-01-31 02:29:12 +04:00
memset ( stk + smp - > enc_key_size , 0 ,
2012-03-08 08:25:00 +04:00
SMP_MAX_ENC_KEY_SIZE - smp - > enc_key_size ) ;
2011-09-05 21:31:31 +04:00
2012-01-16 08:10:31 +04:00
if ( test_and_set_bit ( HCI_CONN_ENCRYPT_PEND , & hcon - > flags ) ) {
2011-09-05 21:31:31 +04:00
reason = SMP_UNSPECIFIED ;
goto error ;
}
hci_le_start_enc ( hcon , ediv , rand , stk ) ;
2012-01-31 02:29:12 +04:00
hcon - > enc_key_size = smp - > enc_key_size ;
2011-09-05 21:31:31 +04:00
} else {
2014-03-18 14:58:24 +04:00
u8 stk [ 16 ] ;
2014-02-28 04:00:28 +04:00
__le64 rand = 0 ;
__le16 ediv = 0 ;
2011-09-05 21:31:31 +04:00
2014-03-18 14:58:24 +04:00
smp_send_cmd ( conn , SMP_CMD_PAIRING_RANDOM , sizeof ( smp - > prnd ) ,
smp - > prnd ) ;
2011-09-05 21:31:31 +04:00
2014-03-18 14:58:24 +04:00
smp_s1 ( tfm , smp - > tk , smp - > prnd , smp - > rrnd , stk ) ;
2011-09-05 21:31:31 +04:00
2012-01-31 02:29:12 +04:00
memset ( stk + smp - > enc_key_size , 0 ,
2013-10-13 16:43:25 +04:00
SMP_MAX_ENC_KEY_SIZE - smp - > enc_key_size ) ;
2011-09-05 21:31:31 +04:00
2013-10-13 13:23:39 +04:00
hci_add_ltk ( hcon - > hdev , & hcon - > dst , hcon - > dst_type ,
2014-02-19 16:57:47 +04:00
HCI_SMP_STK_SLAVE , 0 , stk , smp - > enc_key_size ,
2012-03-08 08:25:00 +04:00
ediv , rand ) ;
2011-09-05 21:31:31 +04:00
}
return ;
error :
2013-11-06 13:24:57 +04:00
smp_failure ( conn , reason ) ;
2011-09-05 21:31:31 +04:00
}
2014-02-28 20:10:03 +04:00
static void smp_reencrypt ( struct work_struct * work )
{
struct smp_chan * smp = container_of ( work , struct smp_chan ,
reencrypt . work ) ;
struct l2cap_conn * conn = smp - > conn ;
struct hci_conn * hcon = conn - > hcon ;
struct smp_ltk * ltk = smp - > ltk ;
BT_DBG ( " " ) ;
hci_le_start_enc ( hcon , ltk - > ediv , ltk - > rand , ltk - > val ) ;
hcon - > enc_key_size = ltk - > enc_size ;
}
2011-09-05 21:31:31 +04:00
static struct smp_chan * smp_chan_create ( struct l2cap_conn * conn )
{
struct smp_chan * smp ;
2013-10-13 16:43:25 +04:00
smp = kzalloc ( sizeof ( * smp ) , GFP_ATOMIC ) ;
2011-09-05 21:31:31 +04:00
if ( ! smp )
return NULL ;
INIT_WORK ( & smp - > confirm , confirm_work ) ;
INIT_WORK ( & smp - > random , random_work ) ;
2014-02-28 20:10:03 +04:00
INIT_DELAYED_WORK ( & smp - > reencrypt , smp_reencrypt ) ;
2011-09-05 21:31:31 +04:00
smp - > conn = conn ;
conn - > smp_chan = smp ;
2011-12-22 04:12:12 +04:00
conn - > hcon - > smp_conn = conn ;
2011-09-05 21:31:31 +04:00
hci_conn_hold ( conn - > hcon ) ;
return smp ;
}
void smp_chan_destroy ( struct l2cap_conn * conn )
{
2011-11-23 20:28:35 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2014-02-18 23:41:34 +04:00
bool complete ;
2011-11-23 20:28:35 +04:00
2012-02-02 01:27:56 +04:00
BUG_ON ( ! smp ) ;
2011-11-23 20:28:35 +04:00
2014-02-28 20:10:03 +04:00
cancel_delayed_work_sync ( & smp - > reencrypt ) ;
2014-02-18 23:41:34 +04:00
complete = test_bit ( SMP_FLAG_COMPLETE , & smp - > smp_flags ) ;
mgmt_smp_complete ( conn - > hcon , complete ) ;
2014-03-09 23:19:17 +04:00
kfree ( smp - > csrk ) ;
kfree ( smp - > slave_csrk ) ;
2014-02-28 12:10:16 +04:00
/* If pairing failed clean up any keys we might have */
if ( ! complete ) {
if ( smp - > ltk ) {
list_del ( & smp - > ltk - > list ) ;
kfree ( smp - > ltk ) ;
}
if ( smp - > slave_ltk ) {
list_del ( & smp - > slave_ltk - > list ) ;
kfree ( smp - > slave_ltk ) ;
}
if ( smp - > remote_irk ) {
list_del ( & smp - > remote_irk - > list ) ;
kfree ( smp - > remote_irk ) ;
}
}
2011-11-23 20:28:35 +04:00
kfree ( smp ) ;
conn - > smp_chan = NULL ;
2011-12-22 04:12:12 +04:00
conn - > hcon - > smp_conn = NULL ;
2013-04-06 22:28:37 +04:00
hci_conn_drop ( conn - > hcon ) ;
2011-09-05 21:31:31 +04:00
}
2011-12-22 04:12:12 +04:00
int smp_user_confirm_reply ( struct hci_conn * hcon , u16 mgmt_op , __le32 passkey )
{
struct l2cap_conn * conn = hcon - > smp_conn ;
struct smp_chan * smp ;
u32 value ;
BT_DBG ( " " ) ;
if ( ! conn )
return - ENOTCONN ;
smp = conn - > smp_chan ;
switch ( mgmt_op ) {
case MGMT_OP_USER_PASSKEY_REPLY :
value = le32_to_cpu ( passkey ) ;
2014-03-18 14:58:24 +04:00
memset ( smp - > tk , 0 , sizeof ( smp - > tk ) ) ;
2011-12-22 04:12:12 +04:00
BT_DBG ( " PassKey: %d " , value ) ;
2014-03-18 14:58:24 +04:00
put_unaligned_le32 ( value , smp - > tk ) ;
2011-12-22 04:12:12 +04:00
/* Fall Through */
case MGMT_OP_USER_CONFIRM_REPLY :
set_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) ;
break ;
case MGMT_OP_USER_PASSKEY_NEG_REPLY :
case MGMT_OP_USER_CONFIRM_NEG_REPLY :
2013-11-06 13:24:57 +04:00
smp_failure ( conn , SMP_PASSKEY_ENTRY_FAILED ) ;
2011-12-22 04:12:12 +04:00
return 0 ;
default :
2013-11-06 13:24:57 +04:00
smp_failure ( conn , SMP_PASSKEY_ENTRY_FAILED ) ;
2011-12-22 04:12:12 +04:00
return - EOPNOTSUPP ;
}
/* If it is our turn to send Pairing Confirm, do so now */
if ( test_bit ( SMP_FLAG_CFM_PENDING , & smp - > smp_flags ) )
queue_work ( hcon - > hdev - > workqueue , & smp - > confirm ) ;
return 0 ;
}
2011-06-10 01:50:53 +04:00
static u8 smp_cmd_pairing_req ( struct l2cap_conn * conn , struct sk_buff * skb )
2011-06-10 01:50:42 +04:00
{
2011-06-14 20:37:42 +04:00
struct smp_cmd_pairing rsp , * req = ( void * ) skb - > data ;
2011-09-05 21:31:31 +04:00
struct smp_chan * smp ;
2011-06-14 20:37:42 +04:00
u8 key_size ;
2011-12-22 04:12:12 +04:00
u8 auth = SMP_AUTH_NONE ;
2011-09-05 21:31:31 +04:00
int ret ;
2011-06-10 01:50:42 +04:00
BT_DBG ( " conn %p " , conn ) ;
2014-02-18 12:19:29 +04:00
if ( skb - > len < sizeof ( * req ) )
return SMP_UNSPECIFIED ;
2011-12-22 04:12:12 +04:00
if ( conn - > hcon - > link_mode & HCI_LM_MASTER )
return SMP_CMD_NOTSUPP ;
2012-01-16 08:10:31 +04:00
if ( ! test_and_set_bit ( HCI_CONN_LE_SMP_PEND , & conn - > hcon - > flags ) )
2011-09-05 21:31:31 +04:00
smp = smp_chan_create ( conn ) ;
2012-07-19 18:03:43 +04:00
else
smp = conn - > smp_chan ;
2011-09-05 21:31:31 +04:00
2012-07-19 18:03:43 +04:00
if ( ! smp )
return SMP_UNSPECIFIED ;
2011-08-20 04:06:51 +04:00
2011-09-05 21:31:30 +04:00
smp - > preq [ 0 ] = SMP_CMD_PAIRING_REQ ;
memcpy ( & smp - > preq [ 1 ] , req , sizeof ( * req ) ) ;
2011-06-14 20:37:42 +04:00
skb_pull ( skb , sizeof ( * req ) ) ;
2011-06-10 01:50:42 +04:00
2011-12-22 04:12:12 +04:00
/* We didn't start the pairing, so match remote */
if ( req - > auth_req & SMP_AUTH_BONDING )
auth = req - > auth_req ;
2011-06-10 01:50:53 +04:00
2012-03-05 22:09:38 +04:00
conn - > hcon - > pending_sec_level = authreq_to_seclevel ( auth ) ;
2011-12-22 04:12:12 +04:00
build_pairing_cmd ( conn , req , & rsp , auth ) ;
2011-06-14 20:37:42 +04:00
key_size = min ( req - > max_key_size , rsp . max_key_size ) ;
if ( check_enc_key_size ( conn , key_size ) )
return SMP_ENC_KEY_SIZE ;
2011-06-10 01:50:42 +04:00
2013-12-02 12:49:03 +04:00
get_random_bytes ( smp - > prnd , sizeof ( smp - > prnd ) ) ;
2011-09-05 21:31:31 +04:00
2011-09-05 21:31:30 +04:00
smp - > prsp [ 0 ] = SMP_CMD_PAIRING_RSP ;
memcpy ( & smp - > prsp [ 1 ] , & rsp , sizeof ( rsp ) ) ;
2011-06-10 01:50:45 +04:00
2011-06-14 20:37:42 +04:00
smp_send_cmd ( conn , SMP_CMD_PAIRING_RSP , sizeof ( rsp ) , & rsp ) ;
2011-06-10 01:50:53 +04:00
2011-12-22 04:12:12 +04:00
/* Request setup of TK */
ret = tk_request ( conn , 0 , auth , rsp . io_capability , req - > io_capability ) ;
if ( ret )
return SMP_UNSPECIFIED ;
2011-06-10 01:50:53 +04:00
return 0 ;
2011-06-10 01:50:42 +04:00
}
2011-06-10 01:50:53 +04:00
static u8 smp_cmd_pairing_rsp ( struct l2cap_conn * conn , struct sk_buff * skb )
2011-06-10 01:50:42 +04:00
{
2011-06-14 20:37:42 +04:00
struct smp_cmd_pairing * req , * rsp = ( void * ) skb - > data ;
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2011-09-05 21:31:31 +04:00
struct hci_dev * hdev = conn - > hcon - > hdev ;
2011-12-22 04:12:12 +04:00
u8 key_size , auth = SMP_AUTH_NONE ;
2011-06-10 01:50:46 +04:00
int ret ;
2011-06-10 01:50:42 +04:00
BT_DBG ( " conn %p " , conn ) ;
2014-02-18 12:19:29 +04:00
if ( skb - > len < sizeof ( * rsp ) )
return SMP_UNSPECIFIED ;
2011-12-22 04:12:12 +04:00
if ( ! ( conn - > hcon - > link_mode & HCI_LM_MASTER ) )
return SMP_CMD_NOTSUPP ;
2011-06-14 20:37:42 +04:00
skb_pull ( skb , sizeof ( * rsp ) ) ;
2011-09-05 21:31:30 +04:00
req = ( void * ) & smp - > preq [ 1 ] ;
2011-06-10 01:50:53 +04:00
2011-06-14 20:37:42 +04:00
key_size = min ( req - > max_key_size , rsp - > max_key_size ) ;
if ( check_enc_key_size ( conn , key_size ) )
return SMP_ENC_KEY_SIZE ;
2013-12-02 12:49:03 +04:00
get_random_bytes ( smp - > prnd , sizeof ( smp - > prnd ) ) ;
2011-06-10 01:50:46 +04:00
2011-09-05 21:31:31 +04:00
smp - > prsp [ 0 ] = SMP_CMD_PAIRING_RSP ;
memcpy ( & smp - > prsp [ 1 ] , rsp , sizeof ( * rsp ) ) ;
2011-06-10 01:50:46 +04:00
2014-03-14 12:53:50 +04:00
/* Update remote key distribution in case the remote cleared
* some bits that we had enabled in our request .
*/
smp - > remote_key_dist & = rsp - > resp_key_dist ;
2011-12-22 04:12:12 +04:00
if ( ( req - > auth_req & SMP_AUTH_BONDING ) & &
2013-10-13 16:43:25 +04:00
( rsp - > auth_req & SMP_AUTH_BONDING ) )
2011-12-22 04:12:12 +04:00
auth = SMP_AUTH_BONDING ;
auth | = ( req - > auth_req | rsp - > auth_req ) & SMP_AUTH_MITM ;
2012-06-06 14:54:15 +04:00
ret = tk_request ( conn , 0 , auth , req - > io_capability , rsp - > io_capability ) ;
2011-12-22 04:12:12 +04:00
if ( ret )
return SMP_UNSPECIFIED ;
set_bit ( SMP_FLAG_CFM_PENDING , & smp - > smp_flags ) ;
/* Can't compose response until we have been confirmed */
2014-03-19 16:14:51 +04:00
if ( test_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) )
queue_work ( hdev - > workqueue , & smp - > confirm ) ;
2011-06-10 01:50:53 +04:00
return 0 ;
2011-06-10 01:50:42 +04:00
}
2011-06-10 01:50:53 +04:00
static u8 smp_cmd_pairing_confirm ( struct l2cap_conn * conn , struct sk_buff * skb )
2011-06-10 01:50:42 +04:00
{
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2011-09-05 21:31:31 +04:00
struct hci_dev * hdev = conn - > hcon - > hdev ;
2011-06-10 01:50:46 +04:00
2011-06-10 01:50:42 +04:00
BT_DBG ( " conn %p %s " , conn , conn - > hcon - > out ? " master " : " slave " ) ;
2014-02-18 12:19:29 +04:00
if ( skb - > len < sizeof ( smp - > pcnf ) )
return SMP_UNSPECIFIED ;
2011-09-05 21:31:30 +04:00
memcpy ( smp - > pcnf , skb - > data , sizeof ( smp - > pcnf ) ) ;
skb_pull ( skb , sizeof ( smp - > pcnf ) ) ;
2011-06-10 01:50:42 +04:00
2014-03-18 14:58:24 +04:00
if ( conn - > hcon - > out )
smp_send_cmd ( conn , SMP_CMD_PAIRING_RANDOM , sizeof ( smp - > prnd ) ,
smp - > prnd ) ;
else if ( test_bit ( SMP_FLAG_TK_VALID , & smp - > smp_flags ) )
2011-09-05 21:31:31 +04:00
queue_work ( hdev - > workqueue , & smp - > confirm ) ;
2014-03-18 14:58:24 +04:00
else
2011-12-22 04:12:12 +04:00
set_bit ( SMP_FLAG_CFM_PENDING , & smp - > smp_flags ) ;
2011-06-10 01:50:53 +04:00
return 0 ;
2011-06-10 01:50:42 +04:00
}
2011-06-10 01:50:53 +04:00
static u8 smp_cmd_pairing_random ( struct l2cap_conn * conn , struct sk_buff * skb )
2011-06-10 01:50:42 +04:00
{
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2011-09-05 21:31:31 +04:00
struct hci_dev * hdev = conn - > hcon - > hdev ;
2011-06-10 01:50:46 +04:00
2011-09-05 21:31:31 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-06-14 20:37:42 +04:00
2014-02-18 12:19:29 +04:00
if ( skb - > len < sizeof ( smp - > rrnd ) )
return SMP_UNSPECIFIED ;
2014-03-18 14:58:24 +04:00
memcpy ( smp - > rrnd , skb - > data , sizeof ( smp - > rrnd ) ) ;
2011-09-05 21:31:31 +04:00
skb_pull ( skb , sizeof ( smp - > rrnd ) ) ;
2011-07-08 01:59:40 +04:00
2011-09-05 21:31:31 +04:00
queue_work ( hdev - > workqueue , & smp - > random ) ;
2011-06-10 01:50:53 +04:00
return 0 ;
2011-06-10 01:50:42 +04:00
}
2012-06-07 10:58:37 +04:00
static u8 smp_ltk_encrypt ( struct l2cap_conn * conn , u8 sec_level )
2011-08-26 03:02:28 +04:00
{
2012-02-03 04:08:01 +04:00
struct smp_ltk * key ;
2011-08-26 03:02:28 +04:00
struct hci_conn * hcon = conn - > hcon ;
2014-01-31 07:40:00 +04:00
key = hci_find_ltk_by_addr ( hcon - > hdev , & hcon - > dst , hcon - > dst_type ,
hcon - > out ) ;
2011-08-26 03:02:28 +04:00
if ( ! key )
return 0 ;
2012-06-07 10:58:37 +04:00
if ( sec_level > BT_SECURITY_MEDIUM & & ! key - > authenticated )
return 0 ;
2012-01-16 08:10:31 +04:00
if ( test_and_set_bit ( HCI_CONN_ENCRYPT_PEND , & hcon - > flags ) )
2011-08-26 03:02:28 +04:00
return 1 ;
2012-02-03 04:08:01 +04:00
hci_le_start_enc ( hcon , key - > ediv , key - > rand , key - > val ) ;
hcon - > enc_key_size = key - > enc_size ;
2011-08-26 03:02:28 +04:00
return 1 ;
}
2013-10-13 16:43:25 +04:00
2011-06-10 01:50:53 +04:00
static u8 smp_cmd_security_req ( struct l2cap_conn * conn , struct sk_buff * skb )
2011-06-10 01:50:42 +04:00
{
struct smp_cmd_security_req * rp = ( void * ) skb - > data ;
struct smp_cmd_pairing cp ;
2011-01-27 03:42:57 +03:00
struct hci_conn * hcon = conn - > hcon ;
2011-09-05 21:31:31 +04:00
struct smp_chan * smp ;
2011-06-10 01:50:42 +04:00
BT_DBG ( " conn %p " , conn ) ;
2014-02-18 12:19:29 +04:00
if ( skb - > len < sizeof ( * rp ) )
return SMP_UNSPECIFIED ;
2013-11-05 13:30:39 +04:00
if ( ! ( conn - > hcon - > link_mode & HCI_LM_MASTER ) )
return SMP_CMD_NOTSUPP ;
2011-12-22 04:12:12 +04:00
hcon - > pending_sec_level = authreq_to_seclevel ( rp - > auth_req ) ;
2011-08-26 03:02:35 +04:00
2012-06-07 10:58:37 +04:00
if ( smp_ltk_encrypt ( conn , hcon - > pending_sec_level ) )
2011-08-26 03:02:28 +04:00
return 0 ;
2012-01-16 08:10:31 +04:00
if ( test_and_set_bit ( HCI_CONN_LE_SMP_PEND , & hcon - > flags ) )
2011-06-10 01:50:53 +04:00
return 0 ;
2011-01-27 03:42:57 +03:00
2011-09-05 21:31:31 +04:00
smp = smp_chan_create ( conn ) ;
2011-08-20 04:06:51 +04:00
2011-06-10 01:50:42 +04:00
skb_pull ( skb , sizeof ( * rp ) ) ;
2011-06-10 01:50:53 +04:00
memset ( & cp , 0 , sizeof ( cp ) ) ;
2011-07-08 01:59:38 +04:00
build_pairing_cmd ( conn , & cp , NULL , rp - > auth_req ) ;
2011-06-10 01:50:42 +04:00
2011-09-05 21:31:30 +04:00
smp - > preq [ 0 ] = SMP_CMD_PAIRING_REQ ;
memcpy ( & smp - > preq [ 1 ] , & cp , sizeof ( cp ) ) ;
2011-06-10 01:50:45 +04:00
2011-06-10 01:50:42 +04:00
smp_send_cmd ( conn , SMP_CMD_PAIRING_REQ , sizeof ( cp ) , & cp ) ;
2011-01-27 03:42:57 +03:00
2011-06-10 01:50:53 +04:00
return 0 ;
2011-06-10 01:50:42 +04:00
}
2013-05-14 19:05:12 +04:00
bool smp_sufficient_security ( struct hci_conn * hcon , u8 sec_level )
{
if ( sec_level = = BT_SECURITY_LOW )
return true ;
if ( hcon - > sec_level > = sec_level )
return true ;
return false ;
}
2012-08-24 04:32:43 +04:00
int smp_conn_security ( struct hci_conn * hcon , __u8 sec_level )
2011-06-10 01:50:40 +04:00
{
2012-08-24 04:32:43 +04:00
struct l2cap_conn * conn = hcon - > l2cap_data ;
2014-03-24 16:39:03 +04:00
struct smp_chan * smp ;
2011-12-22 04:12:12 +04:00
__u8 authreq ;
2011-06-10 01:50:40 +04:00
2011-06-10 01:50:43 +04:00
BT_DBG ( " conn %p hcon %p level 0x%2.2x " , conn , hcon , sec_level ) ;
2014-03-24 16:39:03 +04:00
/* This may be NULL if there's an unexpected disconnection */
if ( ! conn )
return 1 ;
smp = conn - > smp_chan ;
2013-04-24 14:05:32 +04:00
if ( ! test_bit ( HCI_LE_ENABLED , & hcon - > hdev - > dev_flags ) )
2011-07-01 02:20:56 +04:00
return 1 ;
2013-05-14 19:05:12 +04:00
if ( smp_sufficient_security ( hcon , sec_level ) )
2011-06-10 01:50:40 +04:00
return 1 ;
2011-01-27 03:42:57 +03:00
2011-08-26 03:02:28 +04:00
if ( hcon - > link_mode & HCI_LM_MASTER )
2012-06-07 10:58:37 +04:00
if ( smp_ltk_encrypt ( conn , sec_level ) )
2011-07-08 01:59:41 +04:00
goto done ;
2011-08-20 04:06:51 +04:00
2012-01-16 08:10:31 +04:00
if ( test_and_set_bit ( HCI_CONN_LE_SMP_PEND , & hcon - > flags ) )
2011-08-20 04:06:51 +04:00
return 0 ;
2011-09-05 21:31:31 +04:00
smp = smp_chan_create ( conn ) ;
2011-12-22 04:12:12 +04:00
if ( ! smp )
return 1 ;
authreq = seclevel_to_authreq ( sec_level ) ;
2011-08-20 04:06:51 +04:00
2014-03-18 17:42:30 +04:00
/* hcon->auth_type is set by pair_device in mgmt.c. If the MITM
* flag is set we should also set it for the SMP request .
*/
if ( ( hcon - > auth_type & 0x01 ) )
authreq | = SMP_AUTH_MITM ;
2011-08-20 04:06:51 +04:00
if ( hcon - > link_mode & HCI_LM_MASTER ) {
struct smp_cmd_pairing cp ;
2011-06-10 01:50:45 +04:00
2011-12-22 04:12:12 +04:00
build_pairing_cmd ( conn , & cp , NULL , authreq ) ;
2011-09-05 21:31:30 +04:00
smp - > preq [ 0 ] = SMP_CMD_PAIRING_REQ ;
memcpy ( & smp - > preq [ 1 ] , & cp , sizeof ( cp ) ) ;
2011-06-10 01:50:45 +04:00
2011-06-10 01:50:40 +04:00
smp_send_cmd ( conn , SMP_CMD_PAIRING_REQ , sizeof ( cp ) , & cp ) ;
} else {
struct smp_cmd_security_req cp ;
2011-12-22 04:12:12 +04:00
cp . auth_req = authreq ;
2011-06-10 01:50:40 +04:00
smp_send_cmd ( conn , SMP_CMD_SECURITY_REQ , sizeof ( cp ) , & cp ) ;
}
2011-07-08 01:59:41 +04:00
done :
2011-01-27 03:42:57 +03:00
hcon - > pending_sec_level = sec_level ;
2011-06-10 01:50:40 +04:00
return 0 ;
}
2011-07-08 01:59:34 +04:00
static int smp_cmd_encrypt_info ( struct l2cap_conn * conn , struct sk_buff * skb )
{
2011-07-08 01:59:39 +04:00
struct smp_cmd_encrypt_info * rp = ( void * ) skb - > data ;
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2011-07-08 01:59:39 +04:00
2014-02-18 12:19:29 +04:00
BT_DBG ( " conn %p " , conn ) ;
if ( skb - > len < sizeof ( * rp ) )
return SMP_UNSPECIFIED ;
2014-02-18 12:19:37 +04:00
/* Ignore this PDU if it wasn't requested */
if ( ! ( smp - > remote_key_dist & SMP_DIST_ENC_KEY ) )
return 0 ;
2011-07-08 01:59:39 +04:00
skb_pull ( skb , sizeof ( * rp ) ) ;
2011-09-05 21:31:30 +04:00
memcpy ( smp - > tk , rp - > ltk , sizeof ( smp - > tk ) ) ;
2011-07-08 01:59:39 +04:00
2011-07-08 01:59:34 +04:00
return 0 ;
}
static int smp_cmd_master_ident ( struct l2cap_conn * conn , struct sk_buff * skb )
{
2011-07-08 01:59:39 +04:00
struct smp_cmd_master_ident * rp = ( void * ) skb - > data ;
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2012-02-03 04:08:01 +04:00
struct hci_dev * hdev = conn - > hcon - > hdev ;
struct hci_conn * hcon = conn - > hcon ;
2014-02-19 16:57:46 +04:00
struct smp_ltk * ltk ;
2012-02-03 04:08:01 +04:00
u8 authenticated ;
2011-07-08 01:59:39 +04:00
2014-02-18 12:19:29 +04:00
BT_DBG ( " conn %p " , conn ) ;
if ( skb - > len < sizeof ( * rp ) )
return SMP_UNSPECIFIED ;
2014-02-18 12:19:37 +04:00
/* Ignore this PDU if it wasn't requested */
if ( ! ( smp - > remote_key_dist & SMP_DIST_ENC_KEY ) )
return 0 ;
2014-02-27 01:33:43 +04:00
/* Mark the information as received */
smp - > remote_key_dist & = ~ SMP_DIST_ENC_KEY ;
2011-07-08 01:59:39 +04:00
skb_pull ( skb , sizeof ( * rp ) ) ;
2011-07-08 01:59:34 +04:00
2012-02-03 04:08:01 +04:00
hci_dev_lock ( hdev ) ;
2013-10-13 13:23:39 +04:00
authenticated = ( hcon - > sec_level = = BT_SECURITY_HIGH ) ;
2014-02-19 16:57:47 +04:00
ltk = hci_add_ltk ( hdev , & hcon - > dst , hcon - > dst_type , HCI_SMP_LTK ,
2014-02-19 16:57:46 +04:00
authenticated , smp - > tk , smp - > enc_key_size ,
rp - > ediv , rp - > rand ) ;
smp - > ltk = ltk ;
2014-02-18 12:19:36 +04:00
if ( ! ( smp - > remote_key_dist & SMP_DIST_ID_KEY ) )
2014-02-27 01:33:45 +04:00
smp_distribute_keys ( conn ) ;
2012-02-03 04:08:01 +04:00
hci_dev_unlock ( hdev ) ;
2011-07-08 01:59:34 +04:00
return 0 ;
}
2014-02-18 12:19:36 +04:00
static int smp_cmd_ident_info ( struct l2cap_conn * conn , struct sk_buff * skb )
{
struct smp_cmd_ident_info * info = ( void * ) skb - > data ;
struct smp_chan * smp = conn - > smp_chan ;
BT_DBG ( " " ) ;
if ( skb - > len < sizeof ( * info ) )
return SMP_UNSPECIFIED ;
2014-02-18 12:19:37 +04:00
/* Ignore this PDU if it wasn't requested */
if ( ! ( smp - > remote_key_dist & SMP_DIST_ID_KEY ) )
return 0 ;
2014-02-18 12:19:36 +04:00
skb_pull ( skb , sizeof ( * info ) ) ;
memcpy ( smp - > irk , info - > irk , 16 ) ;
return 0 ;
}
static int smp_cmd_ident_addr_info ( struct l2cap_conn * conn ,
struct sk_buff * skb )
{
struct smp_cmd_ident_addr_info * info = ( void * ) skb - > data ;
struct smp_chan * smp = conn - > smp_chan ;
struct hci_conn * hcon = conn - > hcon ;
bdaddr_t rpa ;
BT_DBG ( " " ) ;
if ( skb - > len < sizeof ( * info ) )
return SMP_UNSPECIFIED ;
2014-02-18 12:19:37 +04:00
/* Ignore this PDU if it wasn't requested */
if ( ! ( smp - > remote_key_dist & SMP_DIST_ID_KEY ) )
return 0 ;
2014-02-27 01:33:43 +04:00
/* Mark the information as received */
smp - > remote_key_dist & = ~ SMP_DIST_ID_KEY ;
2014-02-18 12:19:36 +04:00
skb_pull ( skb , sizeof ( * info ) ) ;
2014-02-26 00:24:37 +04:00
/* Strictly speaking the Core Specification (4.1) allows sending
* an empty address which would force us to rely on just the IRK
* as " identity information " . However , since such
* implementations are not known of and in order to not over
* complicate our implementation , simply pretend that we never
* received an IRK for such a device .
*/
if ( ! bacmp ( & info - > bdaddr , BDADDR_ANY ) ) {
BT_ERR ( " Ignoring IRK with no identity address " ) ;
2014-02-27 01:33:45 +04:00
smp_distribute_keys ( conn ) ;
2014-02-26 00:24:37 +04:00
return 0 ;
}
2014-02-18 12:19:36 +04:00
bacpy ( & smp - > id_addr , & info - > bdaddr ) ;
smp - > id_addr_type = info - > addr_type ;
if ( hci_bdaddr_is_rpa ( & hcon - > dst , hcon - > dst_type ) )
bacpy ( & rpa , & hcon - > dst ) ;
else
bacpy ( & rpa , BDADDR_ANY ) ;
2014-02-19 16:57:46 +04:00
smp - > remote_irk = hci_add_irk ( conn - > hcon - > hdev , & smp - > id_addr ,
smp - > id_addr_type , smp - > irk , & rpa ) ;
2014-02-18 12:19:36 +04:00
2014-02-27 01:33:45 +04:00
smp_distribute_keys ( conn ) ;
2014-02-18 12:19:36 +04:00
return 0 ;
}
2014-03-09 23:19:17 +04:00
static int smp_cmd_sign_info ( struct l2cap_conn * conn , struct sk_buff * skb )
{
struct smp_cmd_sign_info * rp = ( void * ) skb - > data ;
struct smp_chan * smp = conn - > smp_chan ;
struct hci_dev * hdev = conn - > hcon - > hdev ;
struct smp_csrk * csrk ;
BT_DBG ( " conn %p " , conn ) ;
if ( skb - > len < sizeof ( * rp ) )
return SMP_UNSPECIFIED ;
/* Ignore this PDU if it wasn't requested */
if ( ! ( smp - > remote_key_dist & SMP_DIST_SIGN ) )
return 0 ;
/* Mark the information as received */
smp - > remote_key_dist & = ~ SMP_DIST_SIGN ;
skb_pull ( skb , sizeof ( * rp ) ) ;
hci_dev_lock ( hdev ) ;
csrk = kzalloc ( sizeof ( * csrk ) , GFP_KERNEL ) ;
if ( csrk ) {
csrk - > master = 0x01 ;
memcpy ( csrk - > val , rp - > csrk , sizeof ( csrk - > val ) ) ;
}
smp - > csrk = csrk ;
if ( ! ( smp - > remote_key_dist & SMP_DIST_SIGN ) )
smp_distribute_keys ( conn ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2011-06-10 01:50:40 +04:00
int smp_sig_channel ( struct l2cap_conn * conn , struct sk_buff * skb )
{
2013-10-03 11:00:57 +04:00
struct hci_conn * hcon = conn - > hcon ;
2013-10-03 12:23:08 +04:00
__u8 code , reason ;
2011-06-10 01:50:40 +04:00
int err = 0 ;
2013-10-03 11:00:57 +04:00
if ( hcon - > type ! = LE_LINK ) {
kfree_skb ( skb ) ;
2013-10-16 12:37:01 +04:00
return 0 ;
2013-10-03 11:00:57 +04:00
}
2013-10-03 12:23:08 +04:00
if ( skb - > len < 1 ) {
kfree_skb ( skb ) ;
return - EILSEQ ;
}
2013-10-18 14:43:00 +04:00
if ( ! test_bit ( HCI_LE_ENABLED , & hcon - > hdev - > dev_flags ) ) {
2011-07-01 02:20:56 +04:00
err = - ENOTSUPP ;
reason = SMP_PAIRING_NOTSUPP ;
goto done ;
}
2013-10-03 12:23:08 +04:00
code = skb - > data [ 0 ] ;
2011-06-10 01:50:40 +04:00
skb_pull ( skb , sizeof ( code ) ) ;
2013-01-29 20:44:23 +04:00
/*
* The SMP context must be initialized for all other PDUs except
* pairing and security requests . If we get any other PDU when
* not initialized simply disconnect ( done if this function
* returns an error ) .
*/
if ( code ! = SMP_CMD_PAIRING_REQ & & code ! = SMP_CMD_SECURITY_REQ & &
! conn - > smp_chan ) {
BT_ERR ( " Unexpected SMP command 0x%02x. Disconnecting. " , code ) ;
kfree_skb ( skb ) ;
return - ENOTSUPP ;
}
2011-06-10 01:50:40 +04:00
switch ( code ) {
case SMP_CMD_PAIRING_REQ :
2011-06-10 01:50:53 +04:00
reason = smp_cmd_pairing_req ( conn , skb ) ;
2011-06-10 01:50:40 +04:00
break ;
case SMP_CMD_PAIRING_FAIL :
2013-11-06 13:24:57 +04:00
smp_failure ( conn , 0 ) ;
2011-06-10 01:50:53 +04:00
reason = 0 ;
err = - EPERM ;
2011-06-10 01:50:40 +04:00
break ;
case SMP_CMD_PAIRING_RSP :
2011-06-10 01:50:53 +04:00
reason = smp_cmd_pairing_rsp ( conn , skb ) ;
2011-06-10 01:50:42 +04:00
break ;
case SMP_CMD_SECURITY_REQ :
2011-06-10 01:50:53 +04:00
reason = smp_cmd_security_req ( conn , skb ) ;
2011-06-10 01:50:42 +04:00
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_PAIRING_CONFIRM :
2011-06-10 01:50:53 +04:00
reason = smp_cmd_pairing_confirm ( conn , skb ) ;
2011-06-10 01:50:42 +04:00
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_PAIRING_RANDOM :
2011-06-10 01:50:53 +04:00
reason = smp_cmd_pairing_random ( conn , skb ) ;
2011-06-10 01:50:42 +04:00
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_ENCRYPT_INFO :
2011-07-08 01:59:34 +04:00
reason = smp_cmd_encrypt_info ( conn , skb ) ;
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_MASTER_IDENT :
2011-07-08 01:59:34 +04:00
reason = smp_cmd_master_ident ( conn , skb ) ;
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_IDENT_INFO :
2014-02-18 12:19:36 +04:00
reason = smp_cmd_ident_info ( conn , skb ) ;
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_IDENT_ADDR_INFO :
2014-02-18 12:19:36 +04:00
reason = smp_cmd_ident_addr_info ( conn , skb ) ;
break ;
2011-06-10 01:50:40 +04:00
case SMP_CMD_SIGN_INFO :
2014-03-09 23:19:17 +04:00
reason = smp_cmd_sign_info ( conn , skb ) ;
2011-07-08 01:59:34 +04:00
break ;
2011-06-10 01:50:40 +04:00
default :
BT_DBG ( " Unknown command code 0x%2.2x " , code ) ;
reason = SMP_CMD_NOTSUPP ;
err = - EOPNOTSUPP ;
2011-06-10 01:50:43 +04:00
goto done ;
2011-06-10 01:50:40 +04:00
}
2011-06-10 01:50:43 +04:00
done :
if ( reason )
2013-11-06 13:24:57 +04:00
smp_failure ( conn , reason ) ;
2011-06-10 01:50:43 +04:00
2011-06-10 01:50:40 +04:00
kfree_skb ( skb ) ;
return err ;
}
2011-07-08 01:59:34 +04:00
2014-02-19 16:57:47 +04:00
static void smp_notify_keys ( struct l2cap_conn * conn )
{
struct smp_chan * smp = conn - > smp_chan ;
struct hci_conn * hcon = conn - > hcon ;
struct hci_dev * hdev = hcon - > hdev ;
2014-03-10 10:38:42 +04:00
struct smp_cmd_pairing * req = ( void * ) & smp - > preq [ 1 ] ;
struct smp_cmd_pairing * rsp = ( void * ) & smp - > prsp [ 1 ] ;
bool persistent ;
2014-02-19 16:57:47 +04:00
2014-03-20 14:54:16 +04:00
if ( smp - > remote_irk ) {
2014-02-19 17:18:31 +04:00
mgmt_new_irk ( hdev , smp - > remote_irk ) ;
2014-03-20 14:54:16 +04:00
/* Now that user space can be considered to know the
* identity address track the connection based on it
* from now on .
*/
bacpy ( & hcon - > dst , & smp - > remote_irk - > bdaddr ) ;
hcon - > dst_type = smp - > remote_irk - > addr_type ;
l2cap_conn_update_id_addr ( hcon ) ;
}
2014-02-19 17:18:31 +04:00
2014-03-10 10:38:42 +04:00
/* The LTKs and CSRKs should be persistent only if both sides
* had the bonding bit set in their authentication requests .
*/
persistent = ! ! ( ( req - > auth_req & rsp - > auth_req ) & SMP_AUTH_BONDING ) ;
2014-03-09 23:19:17 +04:00
if ( smp - > csrk ) {
smp - > csrk - > bdaddr_type = hcon - > dst_type ;
bacpy ( & smp - > csrk - > bdaddr , & hcon - > dst ) ;
2014-03-10 10:38:42 +04:00
mgmt_new_csrk ( hdev , smp - > csrk , persistent ) ;
2014-03-09 23:19:17 +04:00
}
if ( smp - > slave_csrk ) {
smp - > slave_csrk - > bdaddr_type = hcon - > dst_type ;
bacpy ( & smp - > slave_csrk - > bdaddr , & hcon - > dst ) ;
2014-03-10 10:38:42 +04:00
mgmt_new_csrk ( hdev , smp - > slave_csrk , persistent ) ;
2014-03-09 23:19:17 +04:00
}
2014-02-19 16:57:47 +04:00
if ( smp - > ltk ) {
smp - > ltk - > bdaddr_type = hcon - > dst_type ;
bacpy ( & smp - > ltk - > bdaddr , & hcon - > dst ) ;
2014-03-10 10:38:42 +04:00
mgmt_new_ltk ( hdev , smp - > ltk , persistent ) ;
2014-02-19 16:57:47 +04:00
}
if ( smp - > slave_ltk ) {
smp - > slave_ltk - > bdaddr_type = hcon - > dst_type ;
bacpy ( & smp - > slave_ltk - > bdaddr , & hcon - > dst ) ;
2014-03-10 10:38:42 +04:00
mgmt_new_ltk ( hdev , smp - > slave_ltk , persistent ) ;
2014-02-19 16:57:47 +04:00
}
}
2014-02-27 01:33:45 +04:00
int smp_distribute_keys ( struct l2cap_conn * conn )
2011-07-08 01:59:34 +04:00
{
struct smp_cmd_pairing * req , * rsp ;
2011-09-05 21:31:30 +04:00
struct smp_chan * smp = conn - > smp_chan ;
2014-02-22 21:06:31 +04:00
struct hci_conn * hcon = conn - > hcon ;
struct hci_dev * hdev = hcon - > hdev ;
2014-02-28 20:10:02 +04:00
bool ltk_encrypt ;
2011-07-08 01:59:34 +04:00
__u8 * keydist ;
2014-02-27 01:33:45 +04:00
BT_DBG ( " conn %p " , conn ) ;
2011-07-08 01:59:34 +04:00
2014-02-22 21:06:31 +04:00
if ( ! test_bit ( HCI_CONN_LE_SMP_PEND , & hcon - > flags ) )
2011-08-20 04:06:51 +04:00
return 0 ;
2011-09-05 21:31:30 +04:00
rsp = ( void * ) & smp - > prsp [ 1 ] ;
2011-07-08 01:59:34 +04:00
/* The responder sends its keys first */
2014-02-27 01:33:44 +04:00
if ( hcon - > out & & ( smp - > remote_key_dist & 0x07 ) )
2011-07-08 01:59:34 +04:00
return 0 ;
2011-09-05 21:31:30 +04:00
req = ( void * ) & smp - > preq [ 1 ] ;
2011-07-08 01:59:34 +04:00
2014-02-22 21:06:31 +04:00
if ( hcon - > out ) {
2011-07-08 01:59:34 +04:00
keydist = & rsp - > init_key_dist ;
* keydist & = req - > init_key_dist ;
} else {
keydist = & rsp - > resp_key_dist ;
* keydist & = req - > resp_key_dist ;
}
BT_DBG ( " keydist 0x%x " , * keydist ) ;
if ( * keydist & SMP_DIST_ENC_KEY ) {
struct smp_cmd_encrypt_info enc ;
struct smp_cmd_master_ident ident ;
2014-02-19 16:57:46 +04:00
struct smp_ltk * ltk ;
2012-02-03 04:08:01 +04:00
u8 authenticated ;
2011-07-08 01:59:34 +04:00
__le16 ediv ;
2014-02-28 04:00:28 +04:00
__le64 rand ;
2011-07-08 01:59:34 +04:00
get_random_bytes ( enc . ltk , sizeof ( enc . ltk ) ) ;
get_random_bytes ( & ediv , sizeof ( ediv ) ) ;
2014-02-28 04:00:28 +04:00
get_random_bytes ( & rand , sizeof ( rand ) ) ;
2011-07-08 01:59:34 +04:00
smp_send_cmd ( conn , SMP_CMD_ENCRYPT_INFO , sizeof ( enc ) , & enc ) ;
2012-02-03 04:08:01 +04:00
authenticated = hcon - > sec_level = = BT_SECURITY_HIGH ;
2014-02-22 21:06:31 +04:00
ltk = hci_add_ltk ( hdev , & hcon - > dst , hcon - > dst_type ,
2014-02-19 16:57:47 +04:00
HCI_SMP_LTK_SLAVE , authenticated , enc . ltk ,
2014-02-28 04:00:28 +04:00
smp - > enc_key_size , ediv , rand ) ;
2014-02-19 16:57:46 +04:00
smp - > slave_ltk = ltk ;
2011-07-08 01:59:39 +04:00
2012-03-12 14:13:06 +04:00
ident . ediv = ediv ;
2014-02-28 04:00:28 +04:00
ident . rand = rand ;
2011-07-08 01:59:34 +04:00
smp_send_cmd ( conn , SMP_CMD_MASTER_IDENT , sizeof ( ident ) , & ident ) ;
* keydist & = ~ SMP_DIST_ENC_KEY ;
}
if ( * keydist & SMP_DIST_ID_KEY ) {
struct smp_cmd_ident_addr_info addrinfo ;
struct smp_cmd_ident_info idinfo ;
2014-02-22 21:06:32 +04:00
memcpy ( idinfo . irk , hdev - > irk , sizeof ( idinfo . irk ) ) ;
2011-07-08 01:59:34 +04:00
smp_send_cmd ( conn , SMP_CMD_IDENT_INFO , sizeof ( idinfo ) , & idinfo ) ;
2014-02-23 21:42:18 +04:00
/* The hci_conn contains the local identity address
* after the connection has been established .
*
* This is true even when the connection has been
* established using a resolvable random address .
*/
2014-02-22 21:06:31 +04:00
bacpy ( & addrinfo . bdaddr , & hcon - > src ) ;
2014-02-23 21:42:18 +04:00
addrinfo . addr_type = hcon - > src_type ;
2011-07-08 01:59:34 +04:00
smp_send_cmd ( conn , SMP_CMD_IDENT_ADDR_INFO , sizeof ( addrinfo ) ,
2013-10-13 16:43:25 +04:00
& addrinfo ) ;
2011-07-08 01:59:34 +04:00
* keydist & = ~ SMP_DIST_ID_KEY ;
}
if ( * keydist & SMP_DIST_SIGN ) {
struct smp_cmd_sign_info sign ;
2014-03-09 23:19:17 +04:00
struct smp_csrk * csrk ;
2011-07-08 01:59:34 +04:00
2014-03-09 23:19:17 +04:00
/* Generate a new random key */
2011-07-08 01:59:34 +04:00
get_random_bytes ( sign . csrk , sizeof ( sign . csrk ) ) ;
2014-03-09 23:19:17 +04:00
csrk = kzalloc ( sizeof ( * csrk ) , GFP_KERNEL ) ;
if ( csrk ) {
csrk - > master = 0x00 ;
memcpy ( csrk - > val , sign . csrk , sizeof ( csrk - > val ) ) ;
}
smp - > slave_csrk = csrk ;
2011-07-08 01:59:34 +04:00
smp_send_cmd ( conn , SMP_CMD_SIGN_INFO , sizeof ( sign ) , & sign ) ;
* keydist & = ~ SMP_DIST_SIGN ;
}
2014-02-27 01:33:44 +04:00
/* If there are still keys to be received wait for them */
if ( ( smp - > remote_key_dist & 0x07 ) )
return 0 ;
2014-02-28 20:10:02 +04:00
/* Check if we should try to re-encrypt the link with the LTK.
* SMP_FLAG_LTK_ENCRYPT flag is used to track whether we ' ve
* already tried this ( in which case we shouldn ' t try again ) .
*
* The request will trigger an encryption key refresh event
* which will cause a call to auth_cfm and eventually lead to
* l2cap_core . c calling this smp_distribute_keys function again
* and thereby completing the process .
*/
if ( smp - > ltk )
ltk_encrypt = ! test_and_set_bit ( SMP_FLAG_LTK_ENCRYPT ,
& smp - > smp_flags ) ;
else
ltk_encrypt = false ;
2014-02-27 01:33:44 +04:00
2014-02-28 20:10:02 +04:00
/* Re-encrypt the link with LTK if possible */
if ( ltk_encrypt & & hcon - > out ) {
2014-02-28 20:10:03 +04:00
queue_delayed_work ( hdev - > req_workqueue , & smp - > reencrypt ,
SMP_REENCRYPT_TIMEOUT ) ;
2014-02-28 20:10:02 +04:00
} else {
clear_bit ( HCI_CONN_LE_SMP_PEND , & hcon - > flags ) ;
cancel_delayed_work_sync ( & conn - > security_timer ) ;
set_bit ( SMP_FLAG_COMPLETE , & smp - > smp_flags ) ;
smp_notify_keys ( conn ) ;
smp_chan_destroy ( conn ) ;
}
2011-08-20 04:06:51 +04:00
2011-07-08 01:59:34 +04:00
return 0 ;
}