Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
bb8f2cb2
Commit
bb8f2cb2
authored
Sep 27, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://github.com/padovan/bluetooth-next
parents
ed46fdfc
ab0ff76d
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
538 additions
and
287 deletions
+538
-287
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+10
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+21
-4
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+1
-7
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+16
-0
include/net/bluetooth/smp.h
include/net/bluetooth/smp.h
+17
-0
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+1
-1
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+23
-34
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+8
-8
net/bluetooth/hci_sock.c
net/bluetooth/hci_sock.c
+16
-2
net/bluetooth/hci_sysfs.c
net/bluetooth/hci_sysfs.c
+2
-0
net/bluetooth/hidp/core.c
net/bluetooth/hidp/core.c
+3
-0
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+14
-4
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+152
-60
net/bluetooth/smp.c
net/bluetooth/smp.c
+254
-167
No files found.
include/net/bluetooth/hci.h
View file @
bb8f2cb2
...
...
@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr {
bdaddr_t
bdaddr
;
}
__packed
;
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct
hci_cp_write_page_scan_activity
{
__le16
interval
;
__le16
window
;
}
__packed
;
#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
#define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01
#define HCI_OP_LE_SET_EVENT_MASK 0x2001
struct
hci_cp_le_set_event_mask
{
__u8
mask
[
8
];
...
...
include/net/bluetooth/hci_core.h
View file @
bb8f2cb2
...
...
@@ -195,8 +195,6 @@ struct hci_dev {
__u16
init_last_cmd
;
struct
crypto_blkcipher
*
tfm
;
struct
inquiry_cache
inq_cache
;
struct
hci_conn_hash
conn_hash
;
struct
list_head
blacklist
;
...
...
@@ -348,6 +346,7 @@ enum {
HCI_CONN_RSWITCH_PEND
,
HCI_CONN_MODE_CHANGE_PEND
,
HCI_CONN_SCO_SETUP_PEND
,
HCI_CONN_LE_SMP_PEND
,
};
static
inline
void
hci_conn_hash_init
(
struct
hci_dev
*
hdev
)
...
...
@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
}
}
static
inline
unsigned
int
hci_conn_num
(
struct
hci_dev
*
hdev
,
__u8
type
)
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
switch
(
type
)
{
case
ACL_LINK
:
return
h
->
acl_num
;
case
LE_LINK
:
return
h
->
le_num
;
case
SCO_LINK
:
case
ESCO_LINK
:
return
h
->
sco_num
;
default:
return
0
;
}
}
static
inline
struct
hci_conn
*
hci_conn_hash_lookup_handle
(
struct
hci_dev
*
hdev
,
__u16
handle
)
{
...
...
@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
{
if
(
atomic_dec_and_test
(
&
conn
->
refcnt
))
{
unsigned
long
timeo
;
if
(
conn
->
type
==
ACL_LINK
)
{
if
(
conn
->
type
==
ACL_LINK
||
conn
->
type
==
LE_LINK
)
{
del_timer
(
&
conn
->
idle_timer
);
if
(
conn
->
state
==
BT_CONNECTED
)
{
timeo
=
msecs_to_jiffies
(
conn
->
disc_timeout
);
...
...
@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered);
int
mgmt_discoverable
(
u16
index
,
u8
discoverable
);
int
mgmt_connectable
(
u16
index
,
u8
connectable
);
int
mgmt_new_key
(
u16
index
,
struct
link_key
*
key
,
u8
persistent
);
int
mgmt_connected
(
u16
index
,
bdaddr_t
*
bdaddr
);
int
mgmt_connected
(
u16
index
,
bdaddr_t
*
bdaddr
,
u8
link_type
);
int
mgmt_disconnected
(
u16
index
,
bdaddr_t
*
bdaddr
);
int
mgmt_disconnect_failed
(
u16
index
);
int
mgmt_connect_failed
(
u16
index
,
bdaddr_t
*
bdaddr
,
u8
status
);
...
...
@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8
*
eir
);
int
mgmt_remote_name
(
u16
index
,
bdaddr_t
*
bdaddr
,
u8
*
name
);
int
mgmt_discovering
(
u16
index
,
u8
discovering
);
int
mgmt_device_blocked
(
u16
index
,
bdaddr_t
*
bdaddr
);
int
mgmt_device_unblocked
(
u16
index
,
bdaddr_t
*
bdaddr
);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
...
...
include/net/bluetooth/l2cap.h
View file @
bb8f2cb2
...
...
@@ -409,14 +409,8 @@ struct l2cap_conn {
__u8
disc_reason
;
__u8
preq
[
7
];
/* SMP Pairing Request */
__u8
prsp
[
7
];
/* SMP Pairing Response */
__u8
prnd
[
16
];
/* SMP Pairing Random */
__u8
pcnf
[
16
];
/* SMP Pairing Confirm */
__u8
tk
[
16
];
/* SMP Temporary Key */
__u8
smp_key_size
;
struct
timer_list
security_timer
;
struct
smp_chan
*
smp_chan
;
struct
list_head
chan_l
;
rwlock_t
chan_lock
;
...
...
include/net/bluetooth/mgmt.h
View file @
bb8f2cb2
...
...
@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device {
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F
struct
mgmt_cp_set_fast_connectable
{
__u8
enable
;
}
__packed
;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct
mgmt_ev_cmd_complete
{
__le16
opcode
;
...
...
@@ -249,6 +254,7 @@ struct mgmt_ev_new_key {
#define MGMT_EV_CONNECTED 0x000B
struct
mgmt_ev_connected
{
bdaddr_t
bdaddr
;
__u8
link_type
;
}
__packed
;
#define MGMT_EV_DISCONNECTED 0x000C
...
...
@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name {
}
__packed
;
#define MGMT_EV_DISCOVERING 0x0014
#define MGMT_EV_DEVICE_BLOCKED 0x0015
struct
mgmt_ev_device_blocked
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_EV_DEVICE_UNBLOCKED 0x0016
struct
mgmt_ev_device_unblocked
{
bdaddr_t
bdaddr
;
}
__packed
;
include/net/bluetooth/smp.h
View file @
bb8f2cb2
...
...
@@ -115,9 +115,26 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
struct
smp_chan
{
struct
l2cap_conn
*
conn
;
u8
preq
[
7
];
/* SMP Pairing Request */
u8
prsp
[
7
];
/* SMP Pairing Response */
u8
prnd
[
16
];
/* SMP Pairing Random (local) */
u8
rrnd
[
16
];
/* SMP Pairing Random (remote) */
u8
pcnf
[
16
];
/* SMP Pairing Confirm */
u8
tk
[
16
];
/* SMP Temporary Key */
u8
smp_key_size
;
struct
crypto_blkcipher
*
tfm
;
struct
work_struct
confirm
;
struct
work_struct
random
;
};
/* SMP Commands */
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
);
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
);
int
smp_distribute_keys
(
struct
l2cap_conn
*
conn
,
__u8
force
);
void
smp_chan_destroy
(
struct
l2cap_conn
*
conn
);
#endif
/* __SMP_H */
net/bluetooth/hci_conn.c
View file @
bb8f2cb2
...
...
@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
memcpy
(
cp
.
ltk
,
ltk
,
sizeof
(
cp
.
ltk
));
cp
.
ediv
=
ediv
;
memcpy
(
cp
.
rand
,
rand
,
sizeof
(
rand
));
memcpy
(
cp
.
rand
,
rand
,
sizeof
(
cp
.
rand
));
hci_send_cmd
(
hdev
,
HCI_OP_LE_START_ENC
,
sizeof
(
cp
),
&
cp
);
}
...
...
net/bluetooth/hci_core.c
View file @
bb8f2cb2
...
...
@@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
int
hci_blacklist_add
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
bdaddr_list
*
entry
;
int
err
;
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
return
-
EBADF
;
hci_dev_lock_bh
(
hdev
);
if
(
hci_blacklist_lookup
(
hdev
,
bdaddr
))
{
err
=
-
EEXIST
;
goto
err
;
}
if
(
hci_blacklist_lookup
(
hdev
,
bdaddr
))
return
-
EEXIST
;
entry
=
kzalloc
(
sizeof
(
struct
bdaddr_list
),
GFP_KERNEL
);
if
(
!
entry
)
{
err
=
-
ENOMEM
;
goto
err
;
}
if
(
!
entry
)
return
-
ENOMEM
;
bacpy
(
&
entry
->
bdaddr
,
bdaddr
);
list_add
(
&
entry
->
list
,
&
hdev
->
blacklist
);
err
=
0
;
err:
hci_dev_unlock_bh
(
hdev
);
return
err
;
return
mgmt_device_blocked
(
hdev
->
id
,
bdaddr
);
}
int
hci_blacklist_del
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
bdaddr_list
*
entry
;
int
err
=
0
;
hci_dev_lock_bh
(
hdev
);
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
{
hci_blacklist_clear
(
hdev
);
goto
done
;
return
hci_blacklist_clear
(
hdev
);
}
entry
=
hci_blacklist_lookup
(
hdev
,
bdaddr
);
if
(
!
entry
)
{
err
=
-
ENOENT
;
goto
done
;
return
-
ENOENT
;
}
list_del
(
&
entry
->
list
);
kfree
(
entry
);
done:
hci_dev_unlock_bh
(
hdev
);
return
err
;
return
mgmt_device_unblocked
(
hdev
->
id
,
bdaddr
);
}
static
void
hci_clear_adv_cache
(
unsigned
long
arg
)
...
...
@@ -1523,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev)
if
(
!
hdev
->
workqueue
)
goto
nomem
;
hdev
->
tfm
=
crypto_alloc_blkcipher
(
"ecb(aes)"
,
0
,
CRYPTO_ALG_ASYNC
);
if
(
IS_ERR
(
hdev
->
tfm
))
BT_INFO
(
"Failed to load transform for ecb(aes): %ld"
,
PTR_ERR
(
hdev
->
tfm
));
hci_register_sysfs
(
hdev
);
hdev
->
rfkill
=
rfkill_alloc
(
hdev
->
name
,
&
hdev
->
dev
,
...
...
@@ -1576,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
mgmt_index_removed
(
hdev
->
id
);
if
(
!
IS_ERR
(
hdev
->
tfm
))
crypto_free_blkcipher
(
hdev
->
tfm
);
hci_notify
(
hdev
,
HCI_DEV_UNREG
);
if
(
hdev
->
rfkill
)
{
...
...
@@ -2074,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
min
=
c
->
sent
;
conn
=
c
;
}
if
(
hci_conn_num
(
hdev
,
type
)
==
num
)
break
;
}
if
(
conn
)
{
...
...
@@ -2131,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
!
hci_conn_num
(
hdev
,
ACL_LINK
))
return
;
if
(
!
test_bit
(
HCI_RAW
,
&
hdev
->
flags
))
{
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
...
...
@@ -2162,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
!
hci_conn_num
(
hdev
,
SCO_LINK
))
return
;
while
(
hdev
->
sco_cnt
&&
(
conn
=
hci_low_sent
(
hdev
,
SCO_LINK
,
&
quote
)))
{
while
(
quote
--
&&
(
skb
=
skb_dequeue
(
&
conn
->
data_q
)))
{
BT_DBG
(
"skb %p len %d"
,
skb
,
skb
->
len
);
...
...
@@ -2182,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
!
hci_conn_num
(
hdev
,
ESCO_LINK
))
return
;
while
(
hdev
->
sco_cnt
&&
(
conn
=
hci_low_sent
(
hdev
,
ESCO_LINK
,
&
quote
)))
{
while
(
quote
--
&&
(
skb
=
skb_dequeue
(
&
conn
->
data_q
)))
{
BT_DBG
(
"skb %p len %d"
,
skb
,
skb
->
len
);
...
...
@@ -2202,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
!
hci_conn_num
(
hdev
,
LE_LINK
))
return
;
if
(
!
test_bit
(
HCI_RAW
,
&
hdev
->
flags
))
{
/* LE tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
...
...
net/bluetooth/hci_event.c
View file @
bb8f2cb2
...
...
@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if
(
!
cp
)
return
;
hci_dev_lock
(
hdev
);
if
(
cp
->
enable
==
0x01
)
{
del_timer
(
&
hdev
->
adv_timer
);
hci_dev_lock
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_dev_unlock
(
hdev
);
}
else
if
(
cp
->
enable
==
0x00
)
{
mod_timer
(
&
hdev
->
adv_timer
,
jiffies
+
ADV_CLEAR_TIMEOUT
);
}
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_le_ltk_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
return
0
;
/* Only request authentication for SSP connections or non-SSP
* devices with sec_level HIGH */
* devices with sec_level HIGH
or if MITM protection is requested
*/
if
(
!
(
hdev
->
ssp_mode
>
0
&&
conn
->
ssp_mode
>
0
)
&&
conn
->
pending_sec_level
!=
BT_SECURITY_HIGH
)
conn
->
pending_sec_level
!=
BT_SECURITY_HIGH
&&
!
(
conn
->
auth_type
&
0x01
))
return
0
;
return
1
;
...
...
@@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn
->
state
=
BT_CONFIG
;
hci_conn_hold
(
conn
);
conn
->
disc_timeout
=
HCI_DISCONN_TIMEOUT
;
mgmt_connected
(
hdev
->
id
,
&
ev
->
bdaddr
);
mgmt_connected
(
hdev
->
id
,
&
ev
->
bdaddr
,
conn
->
type
);
}
else
conn
->
state
=
BT_CONNECTED
;
...
...
@@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
goto
unlock
;
}
mgmt_connected
(
hdev
->
id
,
&
ev
->
bdaddr
);
mgmt_connected
(
hdev
->
id
,
&
ev
->
bdaddr
,
conn
->
type
);
conn
->
sec_level
=
BT_SECURITY_LOW
;
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
...
...
net/bluetooth/hci_sock.c
View file @
bb8f2cb2
...
...
@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
static
int
hci_sock_blacklist_add
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
{
bdaddr_t
bdaddr
;
int
err
;
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
return
hci_blacklist_add
(
hdev
,
&
bdaddr
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_blacklist_add
(
hdev
,
&
bdaddr
);
hci_dev_unlock_bh
(
hdev
);
return
err
;
}
static
int
hci_sock_blacklist_del
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
{
bdaddr_t
bdaddr
;
int
err
;
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
return
hci_blacklist_del
(
hdev
,
&
bdaddr
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_blacklist_del
(
hdev
,
&
bdaddr
);
hci_dev_unlock_bh
(
hdev
);
return
err
;
}
/* Ioctls that require bound socket */
...
...
net/bluetooth/hci_sysfs.c
View file @
bb8f2cb2
...
...
@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type)
return
"SCO"
;
case
ESCO_LINK
:
return
"eSCO"
;
case
LE_LINK
:
return
"LE"
;
default:
return
"UNKNOWN"
;
}
...
...
net/bluetooth/hidp/core.c
View file @
bb8f2cb2
...
...
@@ -872,6 +872,9 @@ static int hidp_start(struct hid_device *hid)
struct
hidp_session
*
session
=
hid
->
driver_data
;
struct
hid_report
*
report
;
if
(
hid
->
quirks
&
HID_QUIRK_NO_INIT_REPORTS
)
return
0
;
list_for_each_entry
(
report
,
&
hid
->
report_enum
[
HID_INPUT_REPORT
].
report_list
,
list
)
hidp_send_report
(
session
,
report
);
...
...
net/bluetooth/l2cap_core.c
View file @
bb8f2cb2
...
...
@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
if
(
!
conn
->
hcon
->
out
&&
conn
->
hcon
->
type
==
LE_LINK
)
l2cap_le_conn_ready
(
conn
);
if
(
conn
->
hcon
->
out
&&
conn
->
hcon
->
type
==
LE_LINK
)
smp_conn_security
(
conn
,
conn
->
hcon
->
pending_sec_level
);
read_lock
(
&
conn
->
chan_lock
);
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
...
...
@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
del_timer_sync
(
&
conn
->
info_timer
);
if
(
test_
bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
if
(
test_
and_clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
hcon
->
pend
))
{
del_timer
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
}
hcon
->
l2cap_data
=
NULL
;
kfree
(
conn
);
...
...
@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
return
skb
;
}
struct
sk_buff
*
l2cap_create_iframe_pdu
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
,
u16
control
,
u16
sdulen
)
static
struct
sk_buff
*
l2cap_create_iframe_pdu
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
,
u16
control
,
u16
sdulen
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
l2cap_conn
*
conn
=
chan
->
conn
;
...
...
@@ -4093,6 +4100,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG
(
"conn %p"
,
conn
);
if
(
hcon
->
type
==
LE_LINK
)
{
smp_distribute_keys
(
conn
,
0
);
del_timer
(
&
conn
->
security_timer
);
}
read_lock
(
&
conn
->
chan_lock
);
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
...
...
@@ -4105,9 +4117,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if
(
chan
->
scid
==
L2CAP_CID_LE_DATA
)
{
if
(
!
status
&&
encrypt
)
{
chan
->
sec_level
=
hcon
->
sec_level
;
del_timer
(
&
conn
->
security_timer
);
l2cap_chan_ready
(
sk
);
smp_distribute_keys
(
conn
,
0
);
}
bh_unlock_sock
(
sk
);
...
...
net/bluetooth/mgmt.c
View file @
bb8f2cb2
...
...
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct
hci_dev
*
hdev
;
struct
mgmt_cp_load_keys
*
cp
;
u16
key_count
,
expected_len
;
int
i
,
err
;
int
i
;
cp
=
(
void
*
)
data
;
...
...
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key_count
=
get_unaligned_le16
(
&
cp
->
key_count
);
expected_len
=
sizeof
(
*
cp
)
+
key_count
*
sizeof
(
struct
mgmt_key_info
);
if
(
expected_len
>
len
)
{
BT_ERR
(
"load_keys: expected
at least
%u bytes, got %u bytes"
,
expected_len
,
len
);
if
(
expected_len
!=
len
)
{
BT_ERR
(
"load_keys: expected %u bytes, got %u bytes"
,
len
,
expected_
len
);
return
-
EINVAL
;
}
...
...
@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
clear_bit
(
HCI_DEBUG_KEYS
,
&
hdev
->
flags
);
len
-=
sizeof
(
*
cp
);
i
=
0
;
while
(
i
<
len
)
{
struct
mgmt_key_info
*
key
=
(
void
*
)
cp
->
keys
+
i
;
i
+=
sizeof
(
*
key
)
+
key
->
dlen
;
if
(
key
->
type
==
HCI_LK_SMP_LTK
)
{
struct
key_master_id
*
id
=
(
void
*
)
key
->
data
;
if
(
key
->
dlen
!=
sizeof
(
struct
key_master_id
))
continue
;
hci_add_ltk
(
hdev
,
0
,
&
key
->
bdaddr
,
key
->
pin_len
,
id
->
ediv
,
id
->
rand
,
key
->
val
);
continue
;
}
for
(
i
=
0
;
i
<
key_count
;
i
++
)
{
struct
mgmt_key_info
*
key
=
&
cp
->
keys
[
i
];
hci_add_link_key
(
hdev
,
NULL
,
0
,
&
key
->
bdaddr
,
key
->
val
,
key
->
type
,
key
->
pin_len
);
}
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_LOAD_KEYS
,
NULL
,
0
);
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
0
;
}
static
int
remove_key
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
...
...
@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct
hci_dev
*
hdev
;
struct
mgmt_cp_pair_device
*
cp
;
struct
pending_cmd
*
cmd
;
struct
adv_entry
*
entry
;
u8
sec_level
,
auth_type
;
struct
hci_conn
*
conn
;
int
err
;
...
...
@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
hci_dev_lock_bh
(
hdev
);
if
(
cp
->
io_cap
==
0x03
)
{
sec_level
=
BT_SECURITY_MEDIUM
;
sec_level
=
BT_SECURITY_MEDIUM
;
if
(
cp
->
io_cap
==
0x03
)
auth_type
=
HCI_AT_DEDICATED_BONDING
;
}
else
{
sec_level
=
BT_SECURITY_HIGH
;
else
auth_type
=
HCI_AT_DEDICATED_BONDING_MITM
;
}
conn
=
hci_connect
(
hdev
,
ACL_LINK
,
&
cp
->
bdaddr
,
sec_level
,
auth_type
);
entry
=
hci_find_adv_entry
(
hdev
,
&
cp
->
bdaddr
);
if
(
entry
)
conn
=
hci_connect
(
hdev
,
LE_LINK
,
&
cp
->
bdaddr
,
sec_level
,
auth_type
);
else
conn
=
hci_connect
(
hdev
,
ACL_LINK
,
&
cp
->
bdaddr
,
sec_level
,
auth_type
);
if
(
IS_ERR
(
conn
))
{
err
=
PTR_ERR
(
conn
);
goto
unlock
;
...
...
@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto
unlock
;
}
conn
->
connect_cfm_cb
=
pairing_complete_cb
;
/* For LE, just connecting isn't a proof that the pairing finished */
if
(
!
entry
)
conn
->
connect_cfm_cb
=
pairing_complete_cb
;
conn
->
security_cfm_cb
=
pairing_complete_cb
;
conn
->
disconn_cfm_cb
=
pairing_complete_cb
;
conn
->
io_capability
=
cp
->
io_cap
;
...
...
@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_block_device
*
cp
;
struct
pending_cmd
*
cmd
;
struct
mgmt_cp_block_device
*
cp
=
(
void
*
)
data
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
EINVAL
);
...
...
@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
ENODEV
);
hci_dev_lock_bh
(
hdev
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_BLOCK_DEVICE
,
index
,
NULL
,
0
);
if
(
!
cmd
)
{
err
=
-
ENOMEM
;
goto
failed
;
}
err
=
hci_blacklist_add
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
...
...
@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
NULL
,
0
);
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_unblock_device
*
cp
;
struct
pending_cmd
*
cmd
;
struct
mgmt_cp_unblock_device
*
cp
=
(
void
*
)
data
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
EINVAL
);
...
...
@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
ENODEV
);
hci_dev_lock_bh
(
hdev
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_UNBLOCK_DEVICE
,
index
,
NULL
,
0
);
if
(
!
cmd
)
{
err
=
-
ENOMEM
;
goto
failed
;
}
err
=
hci_blacklist_del
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
...
...
@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
NULL
,
0
);
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
}
static
int
set_fast_connectable
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_set_fast_connectable
*
cp
=
(
void
*
)
data
;
struct
hci_cp_write_page_scan_activity
acp
;
u8
type
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
EINVAL
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
ENODEV
);
hci_dev_lock
(
hdev
);
if
(
cp
->
enable
)
{
type
=
PAGE_SCAN_TYPE_INTERLACED
;
acp
.
interval
=
0x0024
;
/* 22.5 msec page scan interval */
}
else
{
type
=
PAGE_SCAN_TYPE_STANDARD
;
/* default */
acp
.
interval
=
0x0800
;
/* default 1.28 sec page scan */
}
acp
.
window
=
0x0012
;
/* default 11.25 msec page scan window */
err
=
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_PAGE_SCAN_ACTIVITY
,
sizeof
(
acp
),
&
acp
);
if
(
err
<
0
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
-
err
);
goto
done
;
}
err
=
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_PAGE_SCAN_TYPE
,
1
,
&
type
);
if
(
err
<
0
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
-
err
);
goto
done
;
}
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
NULL
,
0
);
done:
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case
MGMT_OP_UNBLOCK_DEVICE
:
err
=
unblock_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_SET_FAST_CONNECTABLE
:
err
=
set_fast_connectable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
default:
BT_DBG
(
"Unknown op %u"
,
opcode
);
err
=
cmd_status
(
sk
,
index
,
opcode
,
0x01
);
...
...
@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable)
int
mgmt_new_key
(
u16
index
,
struct
link_key
*
key
,
u8
persistent
)
{
struct
mgmt_ev_new_key
*
ev
;
int
err
,
total
;
total
=
sizeof
(
struct
mgmt_ev_new_key
)
+
key
->
dlen
;
ev
=
kzalloc
(
total
,
GFP_ATOMIC
);
if
(
!
ev
)
return
-
ENOMEM
;
bacpy
(
&
ev
->
key
.
bdaddr
,
&
key
->
bdaddr
);
ev
->
key
.
type
=
key
->
type
;
memcpy
(
ev
->
key
.
val
,
key
->
val
,
16
);
ev
->
key
.
pin_len
=
key
->
pin_len
;
ev
->
key
.
dlen
=
key
->
dlen
;
ev
->
store_hint
=
persistent
;
struct
mgmt_ev_new_key
ev
;
memcpy
(
ev
->
key
.
data
,
key
->
data
,
key
->
dlen
);
err
=
mgmt_event
(
MGMT_EV_NEW_KEY
,
index
,
ev
,
total
,
NULL
);
memset
(
&
ev
,
0
,
sizeof
(
ev
));
kfree
(
ev
);
ev
.
store_hint
=
persistent
;
bacpy
(
&
ev
.
key
.
bdaddr
,
&
key
->
bdaddr
);
ev
.
key
.
type
=
key
->
type
;
memcpy
(
ev
.
key
.
val
,
key
->
val
,
16
);
ev
.
key
.
pin_len
=
key
->
pin_len
;
return
err
;
return
mgmt_event
(
MGMT_EV_NEW_KEY
,
index
,
&
ev
,
sizeof
(
ev
),
NULL
)
;
}
int
mgmt_connected
(
u16
index
,
bdaddr_t
*
bdaddr
)
int
mgmt_connected
(
u16
index
,
bdaddr_t
*
bdaddr
,
u8
link_type
)
{
struct
mgmt_ev_connected
ev
;
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
ev
.
link_type
=
link_type
;
return
mgmt_event
(
MGMT_EV_CONNECTED
,
index
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
...
...
@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
memset
(
&
ev
,
0
,
sizeof
(
ev
));
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
memcpy
(
ev
.
dev_class
,
dev_class
,
sizeof
(
ev
.
dev_class
));
ev
.
rssi
=
rssi
;
if
(
eir
)
memcpy
(
ev
.
eir
,
eir
,
sizeof
(
ev
.
eir
));
if
(
dev_class
)
memcpy
(
ev
.
dev_class
,
dev_class
,
sizeof
(
ev
.
dev_class
));
return
mgmt_event
(
MGMT_EV_DEVICE_FOUND
,
index
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
...
...
@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering)
return
mgmt_event
(
MGMT_EV_DISCOVERING
,
index
,
&
discovering
,
sizeof
(
discovering
),
NULL
);
}
int
mgmt_device_blocked
(
u16
index
,
bdaddr_t
*
bdaddr
)
{
struct
pending_cmd
*
cmd
;
struct
mgmt_ev_device_blocked
ev
;
cmd
=
mgmt_pending_find
(
MGMT_OP_BLOCK_DEVICE
,
index
);
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
return
mgmt_event
(
MGMT_EV_DEVICE_BLOCKED
,
index
,
&
ev
,
sizeof
(
ev
),
cmd
?
cmd
->
sk
:
NULL
);
}
int
mgmt_device_unblocked
(
u16
index
,
bdaddr_t
*
bdaddr
)
{
struct
pending_cmd
*
cmd
;
struct
mgmt_ev_device_unblocked
ev
;
cmd
=
mgmt_pending_find
(
MGMT_OP_UNBLOCK_DEVICE
,
index
);
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
return
mgmt_event
(
MGMT_EV_DEVICE_UNBLOCKED
,
index
,
&
ev
,
sizeof
(
ev
),
cmd
?
cmd
->
sk
:
NULL
);
}
net/bluetooth/smp.c
View file @
bb8f2cb2
...
...
@@ -182,18 +182,9 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
return
;
hci_send_acl
(
conn
->
hcon
,
skb
,
0
);
}
static
__u8
seclevel_to_authreq
(
__u8
level
)
{
switch
(
level
)
{
case
BT_SECURITY_HIGH
:
/* Right now we don't support bonding */
return
SMP_AUTH_MITM
;
default:
return
SMP_AUTH_NONE
;
}
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
}
static
void
build_pairing_cmd
(
struct
l2cap_conn
*
conn
,
...
...
@@ -205,7 +196,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
dist_keys
=
0
;
if
(
test_bit
(
HCI_PAIRABLE
,
&
conn
->
hcon
->
hdev
->
flags
))
{
dist_keys
=
SMP_DIST_ENC_KEY
|
SMP_DIST_ID_KEY
|
SMP_DIST_SIGN
;
dist_keys
=
SMP_DIST_ENC_KEY
;
authreq
|=
SMP_AUTH_BONDING
;
}
...
...
@@ -229,24 +220,184 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
static
u8
check_enc_key_size
(
struct
l2cap_conn
*
conn
,
__u8
max_key_size
)
{
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
if
((
max_key_size
>
SMP_MAX_ENC_KEY_SIZE
)
||
(
max_key_size
<
SMP_MIN_ENC_KEY_SIZE
))
return
SMP_ENC_KEY_SIZE
;
conn
->
smp_key_size
=
max_key_size
;
smp
->
smp_key_size
=
max_key_size
;
return
0
;
}
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
;
struct
crypto_blkcipher
*
tfm
;
struct
smp_cmd_pairing_confirm
cp
;
int
ret
;
u8
res
[
16
],
reason
;
BT_DBG
(
"conn %p"
,
conn
);
tfm
=
crypto_alloc_blkcipher
(
"ecb(aes)"
,
0
,
CRYPTO_ALG_ASYNC
);
if
(
IS_ERR
(
tfm
))
{
reason
=
SMP_UNSPECIFIED
;
goto
error
;
}
smp
->
tfm
=
tfm
;
if
(
conn
->
hcon
->
out
)
ret
=
smp_c1
(
tfm
,
smp
->
tk
,
smp
->
prnd
,
smp
->
preq
,
smp
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
res
);
else
ret
=
smp_c1
(
tfm
,
smp
->
tk
,
smp
->
prnd
,
smp
->
preq
,
smp
->
prsp
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
{
reason
=
SMP_UNSPECIFIED
;
goto
error
;
}
swap128
(
res
,
cp
.
confirm_val
);
smp_send_cmd
(
smp
->
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
return
;
error:
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
smp_chan_destroy
(
conn
);
}
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
;
struct
crypto_blkcipher
*
tfm
=
smp
->
tfm
;
u8
reason
,
confirm
[
16
],
res
[
16
],
key
[
16
];
int
ret
;
if
(
IS_ERR_OR_NULL
(
tfm
))
{
reason
=
SMP_UNSPECIFIED
;
goto
error
;
}
BT_DBG
(
"conn %p %s"
,
conn
,
conn
->
hcon
->
out
?
"master"
:
"slave"
);
if
(
hcon
->
out
)
ret
=
smp_c1
(
tfm
,
smp
->
tk
,
smp
->
rrnd
,
smp
->
preq
,
smp
->
prsp
,
0
,
conn
->
src
,
hcon
->
dst_type
,
conn
->
dst
,
res
);
else
ret
=
smp_c1
(
tfm
,
smp
->
tk
,
smp
->
rrnd
,
smp
->
preq
,
smp
->
prsp
,
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
{
reason
=
SMP_UNSPECIFIED
;
goto
error
;
}
swap128
(
res
,
confirm
);
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
)
{
u8
stk
[
16
],
rand
[
8
];
__le16
ediv
;
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
smp_s1
(
tfm
,
smp
->
tk
,
smp
->
rrnd
,
smp
->
prnd
,
key
);
swap128
(
key
,
stk
);
memset
(
stk
+
smp
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
smp
->
smp_key_size
);
if
(
test_and_set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
{
reason
=
SMP_UNSPECIFIED
;
goto
error
;
}
hci_le_start_enc
(
hcon
,
ediv
,
rand
,
stk
);
hcon
->
enc_key_size
=
smp
->
smp_key_size
;
}
else
{
u8
stk
[
16
],
r
[
16
],
rand
[
8
];
__le16
ediv
;
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
swap128
(
smp
->
prnd
,
r
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
r
),
r
);
smp_s1
(
tfm
,
smp
->
tk
,
smp
->
prnd
,
smp
->
rrnd
,
key
);
swap128
(
key
,
stk
);
memset
(
stk
+
smp
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
smp
->
smp_key_size
);
hci_add_ltk
(
hcon
->
hdev
,
0
,
conn
->
dst
,
smp
->
smp_key_size
,
ediv
,
rand
,
stk
);
}
return
;
error:
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
smp_chan_destroy
(
conn
);
}
static
struct
smp_chan
*
smp_chan_create
(
struct
l2cap_conn
*
conn
)
{
struct
smp_chan
*
smp
;
smp
=
kzalloc
(
sizeof
(
struct
smp_chan
),
GFP_ATOMIC
);
if
(
!
smp
)
return
NULL
;
INIT_WORK
(
&
smp
->
confirm
,
confirm_work
);
INIT_WORK
(
&
smp
->
random
,
random_work
);
smp
->
conn
=
conn
;
conn
->
smp_chan
=
smp
;
hci_conn_hold
(
conn
->
hcon
);
return
smp
;
}
void
smp_chan_destroy
(
struct
l2cap_conn
*
conn
)
{
kfree
(
conn
->
smp_chan
);
hci_conn_put
(
conn
->
hcon
);
}
static
u8
smp_cmd_pairing_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_pairing
rsp
,
*
req
=
(
void
*
)
skb
->
data
;
struct
smp_chan
*
smp
;
u8
key_size
;
int
ret
;
BT_DBG
(
"conn %p"
,
conn
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
req
,
sizeof
(
*
req
));
if
(
!
test_and_set_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
))
smp
=
smp_chan_create
(
conn
);
smp
=
conn
->
smp_chan
;
smp
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
smp
->
preq
[
1
],
req
,
sizeof
(
*
req
));
skb_pull
(
skb
,
sizeof
(
*
req
));
if
(
req
->
oob_flag
)
...
...
@@ -260,32 +411,33 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return
SMP_ENC_KEY_SIZE
;
/* Just works */
memset
(
conn
->
tk
,
0
,
sizeof
(
conn
->
tk
));
memset
(
smp
->
tk
,
0
,
sizeof
(
smp
->
tk
));
ret
=
smp_rand
(
smp
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
conn
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
conn
->
prsp
[
1
],
&
rsp
,
sizeof
(
rsp
));
smp
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
smp
->
prsp
[
1
],
&
rsp
,
sizeof
(
rsp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RSP
,
sizeof
(
rsp
),
&
rsp
);
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
return
0
;
}
static
u8
smp_cmd_pairing_rsp
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_pairing
*
req
,
*
rsp
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing_confirm
cp
;
struct
crypto_blkcipher
*
tfm
=
conn
->
hcon
->
hdev
->
tfm
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
hci_dev
*
hdev
=
conn
->
hcon
->
hdev
;
u8
key_size
;
int
ret
;
u8
res
[
16
],
key_size
;
BT_DBG
(
"conn %p"
,
conn
);
skb_pull
(
skb
,
sizeof
(
*
rsp
));
req
=
(
void
*
)
&
conn
->
preq
[
1
];
req
=
(
void
*
)
&
smp
->
preq
[
1
];
key_size
=
min
(
req
->
max_key_size
,
rsp
->
max_key_size
);
if
(
check_enc_key_size
(
conn
,
key_size
))
...
...
@@ -295,222 +447,154 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
return
SMP_OOB_NOT_AVAIL
;
/* Just works */
memset
(
conn
->
tk
,
0
,
sizeof
(
conn
->
tk
));
conn
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
conn
->
prsp
[
1
],
rsp
,
sizeof
(
*
rsp
));
ret
=
smp_rand
(
conn
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
memset
(
smp
->
tk
,
0
,
sizeof
(
smp
->
tk
));
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
conn
->
preq
,
conn
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
res
);
ret
=
smp_rand
(
smp
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
swap128
(
res
,
cp
.
confirm_val
);
smp
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
smp
->
prsp
[
1
],
rsp
,
sizeof
(
*
rsp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
return
0
;
}
static
u8
smp_cmd_pairing_confirm
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
crypto_blkcipher
*
tfm
=
conn
->
hcon
->
hdev
->
tfm
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
hci_dev
*
hdev
=
conn
->
hcon
->
hdev
;
BT_DBG
(
"conn %p %s"
,
conn
,
conn
->
hcon
->
out
?
"master"
:
"slave"
);
memcpy
(
conn
->
pcnf
,
skb
->
data
,
sizeof
(
conn
->
pcnf
));
skb_pull
(
skb
,
sizeof
(
conn
->
pcnf
));
memcpy
(
smp
->
pcnf
,
skb
->
data
,
sizeof
(
smp
->
pcnf
));
skb_pull
(
skb
,
sizeof
(
smp
->
pcnf
));
if
(
conn
->
hcon
->
out
)
{
u8
random
[
16
];
swap128
(
conn
->
prnd
,
random
);
swap128
(
smp
->
prnd
,
random
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
random
),
random
);
}
else
{
struct
smp_cmd_pairing_confirm
cp
;
int
ret
;
u8
res
[
16
];
ret
=
smp_rand
(
conn
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
conn
->
preq
,
conn
->
prsp
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
return
SMP_CONFIRM_FAILED
;
swap128
(
res
,
cp
.
confirm_val
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
}
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
return
0
;
}
static
u8
smp_cmd_pairing_random
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
crypto_blkcipher
*
tfm
=
hcon
->
hdev
->
tfm
;
int
ret
;
u8
key
[
16
],
res
[
16
],
random
[
16
],
confirm
[
16
];
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
hci_dev
*
hdev
=
conn
->
hcon
->
hdev
;
swap128
(
skb
->
data
,
random
);
skb_pull
(
skb
,
sizeof
(
random
));
if
(
conn
->
hcon
->
out
)
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
random
,
conn
->
preq
,
conn
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
res
);
else
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
random
,
conn
->
preq
,
conn
->
prsp
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
BT_DBG
(
"conn %p %s"
,
conn
,
conn
->
hcon
->
out
?
"master"
:
"slave"
);
swap128
(
res
,
confirm
);
if
(
memcmp
(
conn
->
pcnf
,
confirm
,
sizeof
(
conn
->
pcnf
))
!=
0
)
{
BT_ERR
(
"Pairing failed (confirmation values mismatch)"
);
return
SMP_CONFIRM_FAILED
;
}
if
(
conn
->
hcon
->
out
)
{
u8
stk
[
16
],
rand
[
8
];
__le16
ediv
;
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
BT_DBG
(
"conn %p"
,
conn
);
smp_s1
(
tfm
,
conn
->
tk
,
random
,
conn
->
prnd
,
key
);
swap128
(
key
,
stk
);
swap128
(
skb
->
data
,
smp
->
rrnd
);
skb_pull
(
skb
,
sizeof
(
smp
->
rrnd
)
);
memset
(
stk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
queue_work
(
hdev
->
workqueue
,
&
smp
->
random
);
hci_le_start_enc
(
hcon
,
ediv
,
rand
,
stk
);
hcon
->
enc_key_size
=
conn
->
smp_key_size
;
}
else
{
u8
stk
[
16
],
r
[
16
],
rand
[
8
];
__le16
ediv
;
return
0
;
}
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
static
u8
smp_ltk_encrypt
(
struct
l2cap_conn
*
conn
)
{
struct
link_key
*
key
;
struct
key_master_id
*
master
;
struct
hci_conn
*
hcon
=
conn
->
hcon
;
swap128
(
conn
->
prnd
,
r
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
r
),
r
);
key
=
hci_find_link_key_type
(
hcon
->
hdev
,
conn
->
dst
,
HCI_LK_SMP_LTK
);
if
(
!
key
)
return
0
;
smp_s1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
random
,
key
);
swap128
(
key
,
stk
);
if
(
test_and_set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
return
1
;
memset
(
stk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
master
=
(
void
*
)
key
->
data
;
hci_le_start_enc
(
hcon
,
master
->
ediv
,
master
->
rand
,
key
->
val
);
hcon
->
enc_key_size
=
key
->
pin_len
;
hci_add_ltk
(
conn
->
hcon
->
hdev
,
0
,
conn
->
dst
,
conn
->
smp_key_size
,
ediv
,
rand
,
stk
);
}
return
1
;
return
0
;
}
static
u8
smp_cmd_security_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_security_req
*
rp
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing
cp
;
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
smp_chan
*
smp
;
BT_DBG
(
"conn %p"
,
conn
);
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
hcon
->
pending_sec_level
=
BT_SECURITY_MEDIUM
;
if
(
smp_ltk_encrypt
(
conn
))
return
0
;
if
(
test_and_set_bit
(
HCI_CONN_LE_SMP_PEND
,
&
hcon
->
pend
))
return
0
;
smp
=
smp_chan_create
(
conn
);
skb_pull
(
skb
,
sizeof
(
*
rp
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
rp
->
auth_req
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
smp
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
smp
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
);
return
0
;
}
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
)
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
__u8
authreq
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
BT_DBG
(
"conn %p hcon %p level 0x%2.2x"
,
conn
,
hcon
,
sec_level
);
if
(
!
lmp_host_le_capable
(
hcon
->
hdev
))
return
1
;
if
(
IS_ERR
(
hcon
->
hdev
->
tfm
))
return
1
;
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
return
0
;
if
(
sec_level
==
BT_SECURITY_LOW
)
return
1
;
if
(
hcon
->
sec_level
>=
sec_level
)
return
1
;
authreq
=
seclevel_to_authreq
(
sec_level
);
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
struct
smp_cmd_pairing
cp
;
struct
link_key
*
key
;
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
if
(
smp_ltk_encrypt
(
conn
))
goto
done
;
key
=
hci_find_link_key_type
(
hcon
->
hdev
,
conn
->
dst
,
HCI_LK_SMP_LTK
);
if
(
key
)
{
struct
key_master_id
*
master
=
(
void
*
)
key
->
data
;
if
(
test_and_set_bit
(
HCI_CONN_LE_SMP_PEND
,
&
hcon
->
pend
))
return
0
;
hci_le_start_enc
(
hcon
,
master
->
ediv
,
master
->
rand
,
key
->
val
);
hcon
->
enc_key_size
=
key
->
pin_len
;
smp
=
smp_chan_create
(
conn
);
goto
done
;
}
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
authreq
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
struct
smp_cmd_pairing
cp
;
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
SMP_AUTH_NONE
);
smp
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
smp
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
}
else
{
struct
smp_cmd_security_req
cp
;
cp
.
auth_req
=
authreq
;
cp
.
auth_req
=
SMP_AUTH_NONE
;
smp_send_cmd
(
conn
,
SMP_CMD_SECURITY_REQ
,
sizeof
(
cp
),
&
cp
);
}
done:
hcon
->
pending_sec_level
=
sec_level
;
set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
);
return
0
;
}
...
...
@@ -518,10 +602,11 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
static
int
smp_cmd_encrypt_info
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_encrypt_info
*
rp
=
(
void
*
)
skb
->
data
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
skb_pull
(
skb
,
sizeof
(
*
rp
));
memcpy
(
conn
->
tk
,
rp
->
ltk
,
sizeof
(
conn
->
tk
));
memcpy
(
smp
->
tk
,
rp
->
ltk
,
sizeof
(
smp
->
tk
));
return
0
;
}
...
...
@@ -529,11 +614,12 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
static
int
smp_cmd_master_ident
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_master_ident
*
rp
=
(
void
*
)
skb
->
data
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
skb_pull
(
skb
,
sizeof
(
*
rp
));
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
src
,
conn
->
smp_key_size
,
rp
->
ediv
,
rp
->
rand
,
conn
->
tk
);
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
src
,
smp
->
smp_key_size
,
rp
->
ediv
,
rp
->
rand
,
smp
->
tk
);
smp_distribute_keys
(
conn
,
1
);
...
...
@@ -552,12 +638,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
goto
done
;
}
if
(
IS_ERR
(
conn
->
hcon
->
hdev
->
tfm
))
{
err
=
PTR_ERR
(
conn
->
hcon
->
hdev
->
tfm
);
reason
=
SMP_PAIRING_NOTSUPP
;
goto
done
;
}
skb_pull
(
skb
,
sizeof
(
code
));
switch
(
code
)
{
...
...
@@ -621,20 +701,21 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
int
smp_distribute_keys
(
struct
l2cap_conn
*
conn
,
__u8
force
)
{
struct
smp_cmd_pairing
*
req
,
*
rsp
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
__u8
*
keydist
;
BT_DBG
(
"conn %p force %d"
,
conn
,
force
);
if
(
IS_ERR
(
conn
->
hcon
->
hdev
->
tfm
))
return
PTR_ERR
(
conn
->
hcon
->
hdev
->
tfm
)
;
if
(
!
test_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
))
return
0
;
rsp
=
(
void
*
)
&
conn
->
prsp
[
1
];
rsp
=
(
void
*
)
&
smp
->
prsp
[
1
];
/* The responder sends its keys first */
if
(
!
force
&&
conn
->
hcon
->
out
&&
(
rsp
->
resp_key_dist
&
0x07
))
return
0
;
req
=
(
void
*
)
&
conn
->
preq
[
1
];
req
=
(
void
*
)
&
smp
->
preq
[
1
];
if
(
conn
->
hcon
->
out
)
{
keydist
=
&
rsp
->
init_key_dist
;
...
...
@@ -658,7 +739,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
smp_send_cmd
(
conn
,
SMP_CMD_ENCRYPT_INFO
,
sizeof
(
enc
),
&
enc
);
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
dst
,
conn
->
smp_key_size
,
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
dst
,
smp
->
smp_key_size
,
ediv
,
ident
.
rand
,
enc
.
ltk
);
ident
.
ediv
=
cpu_to_le16
(
ediv
);
...
...
@@ -698,5 +779,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
*
keydist
&=
~
SMP_DIST_SIGN
;
}
if
(
conn
->
hcon
->
out
||
force
)
{
clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
);
del_timer
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
}
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment