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
4b42c542
Commit
4b42c542
authored
Jul 11, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6
Conflicts: net/bluetooth/l2cap_core.c
parents
d8598981
e2fd318e
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
690 additions
and
270 deletions
+690
-270
drivers/bluetooth/ath3k.c
drivers/bluetooth/ath3k.c
+5
-0
drivers/bluetooth/btusb.c
drivers/bluetooth/btusb.c
+11
-1
include/net/bluetooth/bluetooth.h
include/net/bluetooth/bluetooth.h
+8
-4
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+18
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+26
-3
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+20
-5
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+2
-0
include/net/bluetooth/smp.h
include/net/bluetooth/smp.h
+1
-0
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+81
-20
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+85
-2
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+68
-148
net/bluetooth/l2cap_sock.c
net/bluetooth/l2cap_sock.c
+65
-4
net/bluetooth/lib.c
net/bluetooth/lib.c
+21
-2
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+89
-59
net/bluetooth/sco.c
net/bluetooth/sco.c
+2
-2
net/bluetooth/smp.c
net/bluetooth/smp.c
+188
-20
No files found.
drivers/bluetooth/ath3k.c
View file @
4b42c542
...
...
@@ -375,6 +375,11 @@ static int ath3k_probe(struct usb_interface *intf,
/* load patch and sysconfig files for AR3012 */
if
(
id
->
driver_info
&
BTUSB_ATH3012
)
{
/* New firmware with patch and sysconfig files already loaded */
if
(
le16_to_cpu
(
udev
->
descriptor
.
bcdDevice
)
>
0x0001
)
return
-
ENODEV
;
ret
=
ath3k_load_patch
(
udev
);
if
(
ret
<
0
)
{
BT_ERR
(
"Loading patch file failed"
);
...
...
drivers/bluetooth/btusb.c
View file @
4b42c542
...
...
@@ -54,6 +54,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BCM92035 0x10
#define BTUSB_BROKEN_ISOC 0x20
#define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
static
struct
usb_device_id
btusb_table
[]
=
{
/* Generic Bluetooth USB device */
...
...
@@ -110,7 +111,7 @@ static struct usb_device_id blacklist_table[] = {
{
USB_DEVICE
(
0x03f0
,
0x311d
),
.
driver_info
=
BTUSB_IGNORE
},
/* Atheros 3012 with sflash firmware */
{
USB_DEVICE
(
0x0cf3
,
0x3004
),
.
driver_info
=
BTUSB_
IGNORE
},
{
USB_DEVICE
(
0x0cf3
,
0x3004
),
.
driver_info
=
BTUSB_
ATH3012
},
/* Atheros AR5BBU12 with sflash firmware */
{
USB_DEVICE
(
0x0489
,
0xe02c
),
.
driver_info
=
BTUSB_IGNORE
},
...
...
@@ -914,6 +915,15 @@ static int btusb_probe(struct usb_interface *intf,
if
(
ignore_sniffer
&&
id
->
driver_info
&
BTUSB_SNIFFER
)
return
-
ENODEV
;
if
(
id
->
driver_info
&
BTUSB_ATH3012
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
/* Old firmware would otherwise let ath3k driver load
* patch and sysconfig files */
if
(
le16_to_cpu
(
udev
->
descriptor
.
bcdDevice
)
<=
0x0001
)
return
-
ENODEV
;
}
data
=
kzalloc
(
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
!
data
)
return
-
ENOMEM
;
...
...
include/net/bluetooth/bluetooth.h
View file @
4b42c542
...
...
@@ -56,6 +56,7 @@
#define BT_SECURITY 4
struct
bt_security
{
__u8
level
;
__u8
key_size
;
};
#define BT_SECURITY_SDP 0
#define BT_SECURITY_LOW 1
...
...
@@ -76,9 +77,12 @@ struct bt_power {
#define BT_POWER_FORCE_ACTIVE_OFF 0
#define BT_POWER_FORCE_ACTIVE_ON 1
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
__attribute__
((
format
(
printf
,
2
,
3
)))
int
bt_printk
(
const
char
*
level
,
const
char
*
fmt
,
...);
#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg)
/* Connection and socket states */
enum
{
...
...
@@ -204,7 +208,7 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
return
NULL
;
}
int
bt_
err
(
__u16
code
);
int
bt_
to_errno
(
__u16
code
);
extern
int
hci_sock_init
(
void
);
extern
void
hci_sock_cleanup
(
void
);
...
...
include/net/bluetooth/hci.h
View file @
4b42c542
...
...
@@ -211,11 +211,16 @@ enum {
#define LMP_EDR_3S_ESCO 0x80
#define LMP_EXT_INQ 0x01
#define LMP_SIMUL_LE_BR 0x02
#define LMP_SIMPLE_PAIR 0x08
#define LMP_NO_FLUSH 0x40
#define LMP_LSTO 0x01
#define LMP_INQ_TX_PWR 0x02
#define LMP_EXTFEATURES 0x80
/* Extended LMP features */
#define LMP_HOST_LE 0x02
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
...
...
@@ -254,6 +259,10 @@ enum {
#define HCI_LK_UNAUTH_COMBINATION 0x04
#define HCI_LK_AUTH_COMBINATION 0x05
#define HCI_LK_CHANGED_COMBINATION 0x06
/* The spec doesn't define types for SMP keys */
#define HCI_LK_SMP_LTK 0x81
#define HCI_LK_SMP_IRK 0x82
#define HCI_LK_SMP_CSRK 0x83
/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
...
...
@@ -653,6 +662,12 @@ struct hci_rp_read_local_oob_data {
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
struct
hci_cp_write_le_host_supported
{
__u8
le
;
__u8
simul
;
}
__packed
;
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct
hci_rp_read_local_version
{
__u8
status
;
...
...
@@ -676,6 +691,9 @@ struct hci_rp_read_local_features {
}
__packed
;
#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
struct
hci_cp_read_local_ext_features
{
__u8
page
;
}
__packed
;
struct
hci_rp_read_local_ext_features
{
__u8
status
;
__u8
page
;
...
...
include/net/bluetooth/hci_core.h
View file @
4b42c542
...
...
@@ -74,12 +74,28 @@ struct bt_uuid {
u8
svc_hint
;
};
struct
key_master_id
{
__le16
ediv
;
u8
rand
[
8
];
}
__packed
;
struct
link_key_data
{
bdaddr_t
bdaddr
;
u8
type
;
u8
val
[
16
];
u8
pin_len
;
u8
dlen
;
u8
data
[
0
];
}
__packed
;
struct
link_key
{
struct
list_head
list
;
bdaddr_t
bdaddr
;
u8
type
;
u8
val
[
16
];
u8
pin_len
;
u8
dlen
;
u8
data
[
0
];
};
struct
oob_data
{
...
...
@@ -113,6 +129,7 @@ struct hci_dev {
__u8
major_class
;
__u8
minor_class
;
__u8
features
[
8
];
__u8
extfeatures
[
8
];
__u8
commands
[
64
];
__u8
ssp_mode
;
__u8
hci_ver
;
...
...
@@ -223,7 +240,6 @@ struct hci_conn {
struct
list_head
list
;
atomic_t
refcnt
;
spinlock_t
lock
;
bdaddr_t
dst
;
__u8
dst_type
;
...
...
@@ -245,11 +261,11 @@ struct hci_conn {
__u8
sec_level
;
__u8
pending_sec_level
;
__u8
pin_length
;
__u8
enc_key_size
;
__u8
io_capability
;
__u8
power_save
;
__u16
disc_timeout
;
unsigned
long
pend
;
__u8
ltk
[
16
];
__u8
remote_cap
;
__u8
remote_oob
;
...
...
@@ -272,7 +288,6 @@ struct hci_conn {
struct
hci_dev
*
hdev
;
void
*
l2cap_data
;
void
*
sco_data
;
void
*
priv
;
struct
hci_conn
*
link
;
...
...
@@ -538,6 +553,11 @@ int hci_link_keys_clear(struct hci_dev *hdev);
struct
link_key
*
hci_find_link_key
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
hci_add_link_key
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
conn
,
int
new_key
,
bdaddr_t
*
bdaddr
,
u8
*
val
,
u8
type
,
u8
pin_len
);
struct
link_key
*
hci_find_ltk
(
struct
hci_dev
*
hdev
,
__le16
ediv
,
u8
rand
[
8
]);
struct
link_key
*
hci_find_link_key_type
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
);
int
hci_add_ltk
(
struct
hci_dev
*
hdev
,
int
new_key
,
bdaddr_t
*
bdaddr
,
u8
key_size
,
__le16
ediv
,
u8
rand
[
8
],
u8
ltk
[
16
]);
int
hci_remove_link_key
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
hci_remote_oob_data_clear
(
struct
hci_dev
*
hdev
);
...
...
@@ -579,6 +599,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
/* ----- Extended LMP capabilities ----- */
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
/* ----- HCI protocols ----- */
struct
hci_proto
{
char
*
name
;
...
...
include/net/bluetooth/l2cap.h
View file @
4b42c542
...
...
@@ -37,7 +37,6 @@
#define L2CAP_DEFAULT_MONITOR_TO 12000
/* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009
/* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_LE_DEFAULT_MTU 23
#define L2CAP_CONN_TIMEOUT (40000)
/* 40 seconds */
...
...
@@ -130,6 +129,12 @@ struct l2cap_conninfo {
#define L2CAP_SDU_END 0x8000
#define L2CAP_SDU_CONTINUE 0xC000
/* L2CAP Command rej. reasons */
#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define L2CAP_REJ_MTU_EXCEEDED 0x0001
#define L2CAP_REJ_INVALID_CID 0x0002
/* L2CAP structures */
struct
l2cap_hdr
{
__le16
len
;
...
...
@@ -144,8 +149,19 @@ struct l2cap_cmd_hdr {
}
__packed
;
#define L2CAP_CMD_HDR_SIZE 4
struct
l2cap_cmd_rej
{
struct
l2cap_cmd_rej_unk
{
__le16
reason
;
}
__packed
;
struct
l2cap_cmd_rej_mtu
{
__le16
reason
;
__le16
max_mtu
;
}
__packed
;
struct
l2cap_cmd_rej_cid
{
__le16
reason
;
__le16
scid
;
__le16
dcid
;
}
__packed
;
struct
l2cap_conn_req
{
...
...
@@ -352,8 +368,6 @@ struct l2cap_chan {
struct
sk_buff
*
tx_send_head
;
struct
sk_buff_head
tx_q
;
struct
sk_buff_head
srej_q
;
struct
sk_buff_head
busy_q
;
struct
work_struct
busy_work
;
struct
list_head
srej_l
;
struct
list_head
list
;
...
...
@@ -422,6 +436,7 @@ struct l2cap_conn {
struct
l2cap_pinfo
{
struct
bt_sock
bt
;
struct
l2cap_chan
*
chan
;
struct
sk_buff
*
rx_busy_skb
;
};
enum
{
...
...
@@ -449,7 +464,6 @@ enum {
CONN_REJ_ACT
,
CONN_SEND_FBIT
,
CONN_RNR_SENT
,
CONN_SAR_RETRY
,
};
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
...
...
@@ -498,5 +512,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void
l2cap_chan_destroy
(
struct
l2cap_chan
*
chan
);
int
l2cap_chan_connect
(
struct
l2cap_chan
*
chan
);
int
l2cap_chan_send
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
);
void
l2cap_chan_busy
(
struct
l2cap_chan
*
chan
,
int
busy
);
#endif
/* __L2CAP_H */
include/net/bluetooth/mgmt.h
View file @
4b42c542
...
...
@@ -101,6 +101,8 @@ struct mgmt_key_info {
u8
type
;
u8
val
[
16
];
u8
pin_len
;
u8
dlen
;
u8
data
[
0
];
}
__packed
;
#define MGMT_OP_LOAD_KEYS 0x000D
...
...
include/net/bluetooth/smp.h
View file @
4b42c542
...
...
@@ -118,5 +118,6 @@ struct smp_cmd_security_req {
/* 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
);
#endif
/* __SMP_H */
net/bluetooth/hci_core.c
View file @
4b42c542
...
...
@@ -60,8 +60,6 @@ static void hci_tx_task(unsigned long arg);
static
DEFINE_RWLOCK
(
hci_task_lock
);
static
int
enable_smp
;
/* HCI device list */
LIST_HEAD
(
hci_dev_list
);
DEFINE_RWLOCK
(
hci_dev_list_lock
);
...
...
@@ -148,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
switch
(
hdev
->
req_status
)
{
case
HCI_REQ_DONE
:
err
=
-
bt_
err
(
hdev
->
req_result
);
err
=
-
bt_
to_errno
(
hdev
->
req_result
);
break
;
case
HCI_REQ_CANCELED
:
...
...
@@ -542,7 +540,7 @@ int hci_dev_open(__u16 dev)
ret
=
__hci_request
(
hdev
,
hci_init_req
,
0
,
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
if
(
lmp_le_capable
(
hdev
))
if
(
lmp_
host_
le_capable
(
hdev
))
ret
=
__hci_request
(
hdev
,
hci_le_init_req
,
0
,
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
...
...
@@ -1059,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
return
0
;
}
struct
link_key
*
hci_find_ltk
(
struct
hci_dev
*
hdev
,
__le16
ediv
,
u8
rand
[
8
])
{
struct
link_key
*
k
;
list_for_each_entry
(
k
,
&
hdev
->
link_keys
,
list
)
{
struct
key_master_id
*
id
;
if
(
k
->
type
!=
HCI_LK_SMP_LTK
)
continue
;
if
(
k
->
dlen
!=
sizeof
(
*
id
))
continue
;
id
=
(
void
*
)
&
k
->
data
;
if
(
id
->
ediv
==
ediv
&&
(
memcmp
(
rand
,
id
->
rand
,
sizeof
(
id
->
rand
))
==
0
))
return
k
;
}
return
NULL
;
}
EXPORT_SYMBOL
(
hci_find_ltk
);
struct
link_key
*
hci_find_link_key_type
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
)
{
struct
link_key
*
k
;
list_for_each_entry
(
k
,
&
hdev
->
link_keys
,
list
)
if
(
k
->
type
==
type
&&
bacmp
(
bdaddr
,
&
k
->
bdaddr
)
==
0
)
return
k
;
return
NULL
;
}
EXPORT_SYMBOL
(
hci_find_link_key_type
);
int
hci_add_link_key
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
conn
,
int
new_key
,
bdaddr_t
*
bdaddr
,
u8
*
val
,
u8
type
,
u8
pin_len
)
{
...
...
@@ -1114,6 +1148,44 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
return
0
;
}
int
hci_add_ltk
(
struct
hci_dev
*
hdev
,
int
new_key
,
bdaddr_t
*
bdaddr
,
u8
key_size
,
__le16
ediv
,
u8
rand
[
8
],
u8
ltk
[
16
])
{
struct
link_key
*
key
,
*
old_key
;
struct
key_master_id
*
id
;
u8
old_key_type
;
BT_DBG
(
"%s addr %s"
,
hdev
->
name
,
batostr
(
bdaddr
));
old_key
=
hci_find_link_key_type
(
hdev
,
bdaddr
,
HCI_LK_SMP_LTK
);
if
(
old_key
)
{
key
=
old_key
;
old_key_type
=
old_key
->
type
;
}
else
{
key
=
kzalloc
(
sizeof
(
*
key
)
+
sizeof
(
*
id
),
GFP_ATOMIC
);
if
(
!
key
)
return
-
ENOMEM
;
list_add
(
&
key
->
list
,
&
hdev
->
link_keys
);
old_key_type
=
0xff
;
}
key
->
dlen
=
sizeof
(
*
id
);
bacpy
(
&
key
->
bdaddr
,
bdaddr
);
memcpy
(
key
->
val
,
ltk
,
sizeof
(
key
->
val
));
key
->
type
=
HCI_LK_SMP_LTK
;
key
->
pin_len
=
key_size
;
id
=
(
void
*
)
&
key
->
data
;
id
->
ediv
=
ediv
;
memcpy
(
id
->
rand
,
rand
,
sizeof
(
id
->
rand
));
if
(
new_key
)
mgmt_new_key
(
hdev
->
id
,
key
,
old_key_type
);
return
0
;
}
int
hci_remove_link_key
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
link_key
*
key
;
...
...
@@ -1246,7 +1318,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
return
-
EBADF
;
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
hci_blacklist_lookup
(
hdev
,
bdaddr
))
{
err
=
-
EEXIST
;
...
...
@@ -1266,7 +1338,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
err
=
0
;
err:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
return
err
;
}
...
...
@@ -1275,7 +1347,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
struct
bdaddr_list
*
entry
;
int
err
=
0
;
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
{
hci_blacklist_clear
(
hdev
);
...
...
@@ -1292,7 +1364,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
kfree
(
entry
);
done:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
return
err
;
}
...
...
@@ -1368,14 +1440,6 @@ int hci_add_adv_entry(struct hci_dev *hdev,
return
0
;
}
static
struct
crypto_blkcipher
*
alloc_cypher
(
void
)
{
if
(
enable_smp
)
return
crypto_alloc_blkcipher
(
"ecb(aes)"
,
0
,
CRYPTO_ALG_ASYNC
);
return
ERR_PTR
(
-
ENOTSUPP
);
}
/* Register HCI device */
int
hci_register_dev
(
struct
hci_dev
*
hdev
)
{
...
...
@@ -1460,7 +1524,7 @@ int hci_register_dev(struct hci_dev *hdev)
if
(
!
hdev
->
workqueue
)
goto
nomem
;
hdev
->
tfm
=
alloc_cypher
(
);
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
));
...
...
@@ -2352,6 +2416,3 @@ static void hci_cmd_task(unsigned long arg)
}
}
}
module_param
(
enable_smp
,
bool
,
0644
);
MODULE_PARM_DESC
(
enable_smp
,
"Enable SMP support (LE only)"
);
net/bluetooth/hci_event.c
View file @
4b42c542
...
...
@@ -45,6 +45,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
static
int
enable_le
;
/* Handle HCI Event packets */
static
void
hci_cc_inquiry_cancel
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
hci_send_cmd
(
hdev
,
HCI_OP_SET_EVENT_MASK
,
sizeof
(
events
),
events
);
}
static
void
hci_set_le_support
(
struct
hci_dev
*
hdev
)
{
struct
hci_cp_write_le_host_supported
cp
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
if
(
enable_le
)
{
cp
.
le
=
1
;
cp
.
simul
=
!!
(
hdev
->
features
[
6
]
&
LMP_SIMUL_LE_BR
);
}
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_LE_HOST_SUPPORTED
,
sizeof
(
cp
),
&
cp
);
}
static
void
hci_setup
(
struct
hci_dev
*
hdev
)
{
hci_setup_event_mask
(
hdev
);
...
...
@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev)
if
(
hdev
->
features
[
7
]
&
LMP_INQ_TX_PWR
)
hci_send_cmd
(
hdev
,
HCI_OP_READ_INQ_RSP_TX_POWER
,
0
,
NULL
);
if
(
hdev
->
features
[
7
]
&
LMP_EXTFEATURES
)
{
struct
hci_cp_read_local_ext_features
cp
;
cp
.
page
=
0x01
;
hci_send_cmd
(
hdev
,
HCI_OP_READ_LOCAL_EXT_FEATURES
,
sizeof
(
cp
),
&
cp
);
}
if
(
hdev
->
features
[
4
]
&
LMP_LE
)
hci_set_le_support
(
hdev
);
}
static
void
hci_cc_read_local_version
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
hdev
->
features
[
6
],
hdev
->
features
[
7
]);
}
static
void
hci_cc_read_local_ext_features
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_local_ext_features
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
memcpy
(
hdev
->
extfeatures
,
rp
->
features
,
8
);
hci_req_complete
(
hdev
,
HCI_OP_READ_LOCAL_EXT_FEATURES
,
rp
->
status
);
}
static
void
hci_cc_read_buffer_size
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_buffer_size
*
rp
=
(
void
*
)
skb
->
data
;
...
...
@@ -892,6 +934,21 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete
(
hdev
,
HCI_OP_LE_LTK_NEG_REPLY
,
rp
->
status
);
}
static
inline
void
hci_cc_write_le_host_supported
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_cp_read_local_ext_features
cp
;
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
return
;
cp
.
page
=
0x01
;
hci_send_cmd
(
hdev
,
HCI_OP_READ_LOCAL_EXT_FEATURES
,
sizeof
(
cp
),
&
cp
);
}
static
inline
void
hci_cs_inquiry
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
...
...
@@ -1826,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_local_features
(
hdev
,
skb
);
break
;
case
HCI_OP_READ_LOCAL_EXT_FEATURES
:
hci_cc_read_local_ext_features
(
hdev
,
skb
);
break
;
case
HCI_OP_READ_BUFFER_SIZE
:
hci_cc_read_buffer_size
(
hdev
,
skb
);
break
;
...
...
@@ -1894,6 +1955,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_ltk_neg_reply
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_LE_HOST_SUPPORTED
:
hci_cc_write_le_host_supported
(
hdev
,
skb
);
break
;
default:
BT_DBG
(
"%s opcode 0x%x"
,
hdev
->
name
,
opcode
);
break
;
...
...
@@ -2793,21 +2858,36 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
{
struct
hci_ev_le_ltk_req
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_cp_le_ltk_reply
cp
;
struct
hci_cp_le_ltk_neg_reply
neg
;
struct
hci_conn
*
conn
;
struct
link_key
*
ltk
;
BT_DBG
(
"%s handle %d"
,
hdev
->
name
,
cpu_to_le16
(
ev
->
handle
));
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
==
NULL
)
goto
not_found
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
ltk
=
hci_find_ltk
(
hdev
,
ev
->
ediv
,
ev
->
random
);
if
(
ltk
==
NULL
)
goto
not_found
;
memcpy
(
cp
.
ltk
,
ltk
->
val
,
sizeof
(
ltk
->
val
));
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
memcpy
(
cp
.
ltk
,
conn
->
ltk
,
sizeof
(
conn
->
ltk
))
;
conn
->
pin_length
=
ltk
->
pin_len
;
hci_send_cmd
(
hdev
,
HCI_OP_LE_LTK_REPLY
,
sizeof
(
cp
),
&
cp
);
hci_dev_unlock
(
hdev
);
return
;
not_found:
neg
.
handle
=
ev
->
handle
;
hci_send_cmd
(
hdev
,
HCI_OP_LE_LTK_NEG_REPLY
,
sizeof
(
neg
),
&
neg
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_le_meta_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -3022,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
hci_send_to_sock
(
hdev
,
skb
,
NULL
);
kfree_skb
(
skb
);
}
module_param
(
enable_le
,
bool
,
0444
);
MODULE_PARM_DESC
(
enable_le
,
"Enable LE support"
);
net/bluetooth/l2cap_core.c
View file @
4b42c542
...
...
@@ -61,13 +61,9 @@ int disable_ertm;
static
u32
l2cap_feat_mask
=
L2CAP_FEAT_FIXED_CHAN
;
static
u8
l2cap_fixed_chan
[
8
]
=
{
0x02
,
};
static
struct
workqueue_struct
*
_busy_wq
;
static
LIST_HEAD
(
chan_list
);
static
DEFINE_RWLOCK
(
chan_list_lock
);
static
void
l2cap_busy_work
(
struct
work_struct
*
work
);
static
struct
sk_buff
*
l2cap_build_cmd
(
struct
l2cap_conn
*
conn
,
u8
code
,
u8
ident
,
u16
dlen
,
void
*
data
);
static
void
l2cap_send_cmd
(
struct
l2cap_conn
*
conn
,
u8
ident
,
u8
code
,
u16
len
,
...
...
@@ -223,18 +219,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
static
void
l2cap_set_timer
(
struct
l2cap_chan
*
chan
,
struct
timer_list
*
timer
,
long
timeout
)
{
BT_DBG
(
"chan %p state %d timeout %ld"
,
chan
->
sk
,
chan
->
state
,
timeout
);
BT_DBG
(
"chan %p state %d timeout %ld"
,
chan
->
sk
,
chan
->
state
,
timeout
);
if
(
!
mod_timer
(
timer
,
jiffies
+
timeout
))
chan_hold
(
chan
);
if
(
!
mod_timer
(
timer
,
jiffies
+
msecs_to_jiffies
(
timeout
)
))
chan_hold
(
chan
);
}
static
void
l2cap_clear_timer
(
struct
l2cap_chan
*
chan
,
struct
timer_list
*
timer
)
{
BT_DBG
(
"chan %p state %d"
,
chan
,
chan
->
state
);
BT_DBG
(
"chan %p state %d"
,
chan
,
chan
->
state
);
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
chan_put
(
chan
);
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
chan_put
(
chan
);
}
static
void
l2cap_state_change
(
struct
l2cap_chan
*
chan
,
int
state
)
...
...
@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
__clear_ack_timer
(
chan
);
skb_queue_purge
(
&
chan
->
srej_q
);
skb_queue_purge
(
&
chan
->
busy_q
);
list_for_each_entry_safe
(
l
,
tmp
,
&
chan
->
srej_l
,
list
)
{
list_del
(
&
l
->
list
);
...
...
@@ -741,9 +736,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
&
chan
->
conf_state
))
{
/* l2cap_chan_close() calls list_del(chan)
* so release the lock */
read_unlock
_bh
(
&
conn
->
chan_lock
);
read_unlock
(
&
conn
->
chan_lock
);
l2cap_chan_close
(
chan
,
ECONNRESET
);
read_lock
_bh
(
&
conn
->
chan_lock
);
read_lock
(
&
conn
->
chan_lock
);
bh_unlock_sock
(
sk
);
continue
;
}
...
...
@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
setup_timer
(
&
chan
->
ack_timer
,
l2cap_ack_timeout
,
(
unsigned
long
)
chan
);
skb_queue_head_init
(
&
chan
->
srej_q
);
skb_queue_head_init
(
&
chan
->
busy_q
);
INIT_LIST_HEAD
(
&
chan
->
srej_l
);
INIT_WORK
(
&
chan
->
busy_work
,
l2cap_busy_work
);
sk
->
sk_backlog_rcv
=
l2cap_ertm_data_rcv
;
}
...
...
@@ -2284,9 +2277,9 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
static
inline
int
l2cap_command_rej
(
struct
l2cap_conn
*
conn
,
struct
l2cap_cmd_hdr
*
cmd
,
u8
*
data
)
{
struct
l2cap_cmd_rej
*
rej
=
(
struct
l2cap_cmd_rej
*
)
data
;
struct
l2cap_cmd_rej
_unk
*
rej
=
(
struct
l2cap_cmd_rej_unk
*
)
data
;
if
(
rej
->
reason
!=
0x0000
)
if
(
rej
->
reason
!=
L2CAP_REJ_NOT_UNDERSTOOD
)
return
0
;
if
((
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
&&
...
...
@@ -2532,9 +2525,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if
((
bt_sk
(
sk
)
->
defer_setup
&&
chan
->
state
!=
BT_CONNECT2
)
||
(
!
bt_sk
(
sk
)
->
defer_setup
&&
chan
->
state
!=
BT_CONFIG
))
{
struct
l2cap_cmd_rej
rej
;
struct
l2cap_cmd_rej_cid
rej
;
rej
.
reason
=
cpu_to_le16
(
L2CAP_REJ_INVALID_CID
);
rej
.
scid
=
cpu_to_le16
(
chan
->
scid
);
rej
.
dcid
=
cpu_to_le16
(
chan
->
dcid
);
rej
.
reason
=
cpu_to_le16
(
0x0002
);
l2cap_send_cmd
(
conn
,
cmd
->
ident
,
L2CAP_COMMAND_REJ
,
sizeof
(
rej
),
&
rej
);
goto
unlock
;
...
...
@@ -3025,12 +3021,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
err
=
l2cap_bredr_sig_cmd
(
conn
,
&
cmd
,
cmd_len
,
data
);
if
(
err
)
{
struct
l2cap_cmd_rej
rej
;
struct
l2cap_cmd_rej
_unk
rej
;
BT_ERR
(
"Wrong link type (%d)"
,
err
);
/* FIXME: Map err to a valid reason */
rej
.
reason
=
cpu_to_le16
(
0
);
rej
.
reason
=
cpu_to_le16
(
L2CAP_REJ_NOT_UNDERSTOOD
);
l2cap_send_cmd
(
conn
,
cmd
.
ident
,
L2CAP_COMMAND_REJ
,
sizeof
(
rej
),
&
rej
);
}
...
...
@@ -3183,32 +3179,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
if
(
!
chan
->
sdu
)
goto
disconnect
;
if
(
!
test_bit
(
CONN_SAR_RETRY
,
&
chan
->
conn_state
))
{
chan
->
partial_sdu_len
+=
skb
->
len
;
chan
->
partial_sdu_len
+=
skb
->
len
;
if
(
chan
->
partial_sdu_len
>
chan
->
imtu
)
goto
drop
;
if
(
chan
->
partial_sdu_len
>
chan
->
imtu
)
goto
drop
;
if
(
chan
->
partial_sdu_len
!=
chan
->
sdu_len
)
goto
drop
;
if
(
chan
->
partial_sdu_len
!=
chan
->
sdu_len
)
goto
drop
;
memcpy
(
skb_put
(
chan
->
sdu
,
skb
->
len
),
skb
->
data
,
skb
->
len
);
}
memcpy
(
skb_put
(
chan
->
sdu
,
skb
->
len
),
skb
->
data
,
skb
->
len
);
_skb
=
skb_clone
(
chan
->
sdu
,
GFP_ATOMIC
);
if
(
!
_skb
)
{
set_bit
(
CONN_SAR_RETRY
,
&
chan
->
conn_state
);
return
-
ENOMEM
;
}
err
=
chan
->
ops
->
recv
(
chan
->
data
,
_skb
);
if
(
err
<
0
)
{
kfree_skb
(
_skb
);
set_bit
(
CONN_SAR_RETRY
,
&
chan
->
conn_state
);
return
err
;
}
clear_bit
(
CONN_SAR_RETRY
,
&
chan
->
conn_state
);
clear_bit
(
CONN_SAR_SDU
,
&
chan
->
conn_state
);
kfree_skb
(
chan
->
sdu
);
...
...
@@ -3228,22 +3219,26 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
return
0
;
}
static
int
l2cap_try_push_rx_skb
(
struct
l2cap_chan
*
chan
)
static
void
l2cap_ertm_enter_local_busy
(
struct
l2cap_chan
*
chan
)
{
struct
sk_buff
*
skb
;
u16
control
;
int
err
;
while
((
skb
=
skb_dequeue
(
&
chan
->
busy_q
)))
{
control
=
bt_cb
(
skb
)
->
sar
<<
L2CAP_CTRL_SAR_SHIFT
;
err
=
l2cap_ertm_reassembly_sdu
(
chan
,
skb
,
control
);
if
(
err
<
0
)
{
skb_queue_head
(
&
chan
->
busy_q
,
skb
);
return
-
EBUSY
;
}
BT_DBG
(
"chan %p, Enter local busy"
,
chan
);
chan
->
buffer_seq
=
(
chan
->
buffer_seq
+
1
)
%
64
;
}
set_bit
(
CONN_LOCAL_BUSY
,
&
chan
->
conn_state
);
control
=
chan
->
buffer_seq
<<
L2CAP_CTRL_REQSEQ_SHIFT
;
control
|=
L2CAP_SUPER_RCV_NOT_READY
;
l2cap_send_sframe
(
chan
,
control
);
set_bit
(
CONN_RNR_SENT
,
&
chan
->
conn_state
);
__clear_ack_timer
(
chan
);
}
static
void
l2cap_ertm_exit_local_busy
(
struct
l2cap_chan
*
chan
)
{
u16
control
;
if
(
!
test_bit
(
CONN_RNR_SENT
,
&
chan
->
conn_state
))
goto
done
;
...
...
@@ -3263,93 +3258,16 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
clear_bit
(
CONN_RNR_SENT
,
&
chan
->
conn_state
);
BT_DBG
(
"chan %p, Exit local busy"
,
chan
);
return
0
;
}
static
void
l2cap_busy_work
(
struct
work_struct
*
work
)
void
l2cap_chan_busy
(
struct
l2cap_chan
*
chan
,
int
busy
)
{
DECLARE_WAITQUEUE
(
wait
,
current
);
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
busy_work
);
struct
sock
*
sk
=
chan
->
sk
;
int
n_tries
=
0
,
timeo
=
HZ
/
5
,
err
;
struct
sk_buff
*
skb
;
lock_sock
(
sk
);
add_wait_queue
(
sk_sleep
(
sk
),
&
wait
);
while
((
skb
=
skb_peek
(
&
chan
->
busy_q
)))
{
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
n_tries
++
>
L2CAP_LOCAL_BUSY_TRIES
)
{
err
=
-
EBUSY
;
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
EBUSY
);
break
;
}
if
(
!
timeo
)
timeo
=
HZ
/
5
;
if
(
signal_pending
(
current
))
{
err
=
sock_intr_errno
(
timeo
);
break
;
}
release_sock
(
sk
);
timeo
=
schedule_timeout
(
timeo
);
lock_sock
(
sk
);
err
=
sock_error
(
sk
);
if
(
err
)
break
;
if
(
l2cap_try_push_rx_skb
(
chan
)
==
0
)
break
;
}
set_current_state
(
TASK_RUNNING
);
remove_wait_queue
(
sk_sleep
(
sk
),
&
wait
);
release_sock
(
sk
);
}
static
int
l2cap_push_rx_skb
(
struct
l2cap_chan
*
chan
,
struct
sk_buff
*
skb
,
u16
control
)
{
int
sctrl
,
err
;
if
(
test_bit
(
CONN_LOCAL_BUSY
,
&
chan
->
conn_state
))
{
bt_cb
(
skb
)
->
sar
=
control
>>
L2CAP_CTRL_SAR_SHIFT
;
__skb_queue_tail
(
&
chan
->
busy_q
,
skb
);
return
l2cap_try_push_rx_skb
(
chan
);
}
err
=
l2cap_ertm_reassembly_sdu
(
chan
,
skb
,
control
);
if
(
err
>=
0
)
{
chan
->
buffer_seq
=
(
chan
->
buffer_seq
+
1
)
%
64
;
return
err
;
if
(
chan
->
mode
==
L2CAP_MODE_ERTM
)
{
if
(
busy
)
l2cap_ertm_enter_local_busy
(
chan
);
else
l2cap_ertm_exit_local_busy
(
chan
);
}
/* Busy Condition */
BT_DBG
(
"chan %p, Enter local busy"
,
chan
);
set_bit
(
CONN_LOCAL_BUSY
,
&
chan
->
conn_state
);
bt_cb
(
skb
)
->
sar
=
control
>>
L2CAP_CTRL_SAR_SHIFT
;
__skb_queue_tail
(
&
chan
->
busy_q
,
skb
);
sctrl
=
chan
->
buffer_seq
<<
L2CAP_CTRL_REQSEQ_SHIFT
;
sctrl
|=
L2CAP_SUPER_RCV_NOT_READY
;
l2cap_send_sframe
(
chan
,
sctrl
);
set_bit
(
CONN_RNR_SENT
,
&
chan
->
conn_state
);
__clear_ack_timer
(
chan
);
queue_work
(
_busy_wq
,
&
chan
->
busy_work
);
return
err
;
}
static
int
l2cap_streaming_reassembly_sdu
(
struct
l2cap_chan
*
chan
,
struct
sk_buff
*
skb
,
u16
control
)
...
...
@@ -3450,13 +3368,22 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
struct
sk_buff
*
skb
;
u16
control
;
while
((
skb
=
skb_peek
(
&
chan
->
srej_q
)))
{
while
((
skb
=
skb_peek
(
&
chan
->
srej_q
))
&&
!
test_bit
(
CONN_LOCAL_BUSY
,
&
chan
->
conn_state
))
{
int
err
;
if
(
bt_cb
(
skb
)
->
tx_seq
!=
tx_seq
)
break
;
skb
=
skb_dequeue
(
&
chan
->
srej_q
);
control
=
bt_cb
(
skb
)
->
sar
<<
L2CAP_CTRL_SAR_SHIFT
;
l2cap_ertm_reassembly_sdu
(
chan
,
skb
,
control
);
err
=
l2cap_ertm_reassembly_sdu
(
chan
,
skb
,
control
);
if
(
err
<
0
)
{
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
ECONNRESET
);
break
;
}
chan
->
buffer_seq_srej
=
(
chan
->
buffer_seq_srej
+
1
)
%
64
;
tx_seq
=
(
tx_seq
+
1
)
%
64
;
...
...
@@ -3523,9 +3450,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
chan
->
expected_ack_seq
=
req_seq
;
l2cap_drop_acked_frames
(
chan
);
if
(
tx_seq
==
chan
->
expected_tx_seq
)
goto
expected
;
tx_seq_offset
=
(
tx_seq
-
chan
->
buffer_seq
)
%
64
;
if
(
tx_seq_offset
<
0
)
tx_seq_offset
+=
64
;
...
...
@@ -3539,6 +3463,9 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
if
(
test_bit
(
CONN_LOCAL_BUSY
,
&
chan
->
conn_state
))
goto
drop
;
if
(
tx_seq
==
chan
->
expected_tx_seq
)
goto
expected
;
if
(
test_bit
(
CONN_SREJ_SENT
,
&
chan
->
conn_state
))
{
struct
srej_list
*
first
;
...
...
@@ -3590,7 +3517,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
chan
->
buffer_seq_srej
=
chan
->
buffer_seq
;
__skb_queue_head_init
(
&
chan
->
srej_q
);
__skb_queue_head_init
(
&
chan
->
busy_q
);
l2cap_add_to_srej_queue
(
chan
,
skb
,
tx_seq
,
sar
);
set_bit
(
CONN_SEND_PBIT
,
&
chan
->
conn_state
);
...
...
@@ -3611,9 +3537,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return
0
;
}
err
=
l2cap_push_rx_skb
(
chan
,
skb
,
rx_control
);
if
(
err
<
0
)
return
0
;
err
=
l2cap_ertm_reassembly_sdu
(
chan
,
skb
,
rx_control
);
chan
->
buffer_seq
=
(
chan
->
buffer_seq
+
1
)
%
64
;
if
(
err
<
0
)
{
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
ECONNRESET
);
return
err
;
}
if
(
rx_control
&
L2CAP_CTRL_FINAL
)
{
if
(
!
test_and_clear_bit
(
CONN_REJ_ACT
,
&
chan
->
conn_state
))
...
...
@@ -4108,7 +4037,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
if
(
conn
)
l2cap_conn_ready
(
conn
);
}
else
l2cap_conn_del
(
hcon
,
bt_
err
(
status
));
l2cap_conn_del
(
hcon
,
bt_
to_errno
(
status
));
return
0
;
}
...
...
@@ -4132,7 +4061,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
if
(
!
(
hcon
->
type
==
ACL_LINK
||
hcon
->
type
==
LE_LINK
))
return
-
EINVAL
;
l2cap_conn_del
(
hcon
,
bt_
err
(
reason
));
l2cap_conn_del
(
hcon
,
bt_
to_errno
(
reason
));
return
0
;
}
...
...
@@ -4178,6 +4107,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 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
);
...
...
@@ -4415,12 +4345,6 @@ int __init l2cap_init(void)
if
(
err
<
0
)
return
err
;
_busy_wq
=
create_singlethread_workqueue
(
"l2cap"
);
if
(
!
_busy_wq
)
{
err
=
-
ENOMEM
;
goto
error
;
}
err
=
hci_register_proto
(
&
l2cap_hci_proto
);
if
(
err
<
0
)
{
BT_ERR
(
"L2CAP protocol registration failed"
);
...
...
@@ -4438,7 +4362,6 @@ int __init l2cap_init(void)
return
0
;
error:
destroy_workqueue
(
_busy_wq
);
l2cap_cleanup_sockets
();
return
err
;
}
...
...
@@ -4447,9 +4370,6 @@ void l2cap_exit(void)
{
debugfs_remove
(
l2cap_debugfs
);
flush_workqueue
(
_busy_wq
);
destroy_workqueue
(
_busy_wq
);
if
(
hci_unregister_proto
(
&
l2cap_hci_proto
)
<
0
)
BT_ERR
(
"L2CAP protocol unregistration failed"
);
...
...
net/bluetooth/l2cap_sock.c
View file @
4b42c542
...
...
@@ -422,8 +422,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break
;
}
memset
(
&
sec
,
0
,
sizeof
(
sec
));
sec
.
level
=
chan
->
sec_level
;
if
(
sk
->
sk_state
==
BT_CONNECTED
)
sec
.
key_size
=
chan
->
conn
->
hcon
->
enc_key_size
;
len
=
min_t
(
unsigned
int
,
len
,
sizeof
(
sec
));
if
(
copy_to_user
(
optval
,
(
char
*
)
&
sec
,
len
))
err
=
-
EFAULT
;
...
...
@@ -711,13 +715,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
static
int
l2cap_sock_recvmsg
(
struct
kiocb
*
iocb
,
struct
socket
*
sock
,
struct
msghdr
*
msg
,
size_t
len
,
int
flags
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
l2cap_pinfo
*
pi
=
l2cap_pi
(
sk
);
int
err
;
lock_sock
(
sk
);
if
(
sk
->
sk_state
==
BT_CONNECT2
&&
bt_sk
(
sk
)
->
defer_setup
)
{
sk
->
sk_state
=
BT_CONFIG
;
__l2cap_connect_rsp_defer
(
l2cap_pi
(
sk
)
->
chan
);
__l2cap_connect_rsp_defer
(
pi
->
chan
);
release_sock
(
sk
);
return
0
;
}
...
...
@@ -725,9 +731,37 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
release_sock
(
sk
);
if
(
sock
->
type
==
SOCK_STREAM
)
return
bt_sock_stream_recvmsg
(
iocb
,
sock
,
msg
,
len
,
flags
);
err
=
bt_sock_stream_recvmsg
(
iocb
,
sock
,
msg
,
len
,
flags
);
else
err
=
bt_sock_recvmsg
(
iocb
,
sock
,
msg
,
len
,
flags
);
if
(
pi
->
chan
->
mode
!=
L2CAP_MODE_ERTM
)
return
err
;
/* Attempt to put pending rx data in the socket buffer */
lock_sock
(
sk
);
if
(
!
test_bit
(
CONN_LOCAL_BUSY
,
&
pi
->
chan
->
conn_state
))
goto
done
;
if
(
pi
->
rx_busy_skb
)
{
if
(
!
sock_queue_rcv_skb
(
sk
,
pi
->
rx_busy_skb
))
pi
->
rx_busy_skb
=
NULL
;
else
goto
done
;
}
return
bt_sock_recvmsg
(
iocb
,
sock
,
msg
,
len
,
flags
);
/* Restore data flow when half of the receive buffer is
* available. This avoids resending large numbers of
* frames.
*/
if
(
atomic_read
(
&
sk
->
sk_rmem_alloc
)
<=
sk
->
sk_rcvbuf
>>
1
)
l2cap_chan_busy
(
pi
->
chan
,
0
);
done:
release_sock
(
sk
);
return
err
;
}
/* Kill socket (only if zapped and orphan)
...
...
@@ -811,9 +845,31 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
static
int
l2cap_sock_recv_cb
(
void
*
data
,
struct
sk_buff
*
skb
)
{
int
err
;
struct
sock
*
sk
=
data
;
struct
l2cap_pinfo
*
pi
=
l2cap_pi
(
sk
);
return
sock_queue_rcv_skb
(
sk
,
skb
);
if
(
pi
->
rx_busy_skb
)
return
-
ENOMEM
;
err
=
sock_queue_rcv_skb
(
sk
,
skb
);
/* For ERTM, handle one skb that doesn't fit into the recv
* buffer. This is important to do because the data frames
* have already been acked, so the skb cannot be discarded.
*
* Notify the l2cap core that the buffer is full, so the
* LOCAL_BUSY state is entered and no more frames are
* acked and reassembled until there is buffer space
* available.
*/
if
(
err
<
0
&&
pi
->
chan
->
mode
==
L2CAP_MODE_ERTM
)
{
pi
->
rx_busy_skb
=
skb
;
l2cap_chan_busy
(
pi
->
chan
,
1
);
err
=
0
;
}
return
err
;
}
static
void
l2cap_sock_close_cb
(
void
*
data
)
...
...
@@ -842,6 +898,11 @@ static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG
(
"sk %p"
,
sk
);
if
(
l2cap_pi
(
sk
)
->
rx_busy_skb
)
{
kfree_skb
(
l2cap_pi
(
sk
)
->
rx_busy_skb
);
l2cap_pi
(
sk
)
->
rx_busy_skb
=
NULL
;
}
skb_queue_purge
(
&
sk
->
sk_receive_queue
);
skb_queue_purge
(
&
sk
->
sk_write_queue
);
}
...
...
net/bluetooth/lib.c
View file @
4b42c542
...
...
@@ -59,7 +59,7 @@ char *batostr(bdaddr_t *ba)
EXPORT_SYMBOL
(
batostr
);
/* Bluetooth error codes to Unix errno mapping */
int
bt_
err
(
__u16
code
)
int
bt_
to_errno
(
__u16
code
)
{
switch
(
code
)
{
case
0
:
...
...
@@ -149,4 +149,23 @@ int bt_err(__u16 code)
return
ENOSYS
;
}
}
EXPORT_SYMBOL
(
bt_err
);
EXPORT_SYMBOL
(
bt_to_errno
);
int
bt_printk
(
const
char
*
level
,
const
char
*
format
,
...)
{
struct
va_format
vaf
;
va_list
args
;
int
r
;
va_start
(
args
,
format
);
vaf
.
fmt
=
format
;
vaf
.
va
=
&
args
;
r
=
printk
(
"%sBluetooth: %pV
\n
"
,
level
,
&
vaf
);
va_end
(
args
);
return
r
;
}
EXPORT_SYMBOL
(
bt_printk
);
net/bluetooth/mgmt.c
View file @
4b42c542
...
...
@@ -179,7 +179,7 @@ static int read_controller_info(struct sock *sk, u16 index)
hci_del_off_timer
(
hdev
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
set_bit
(
HCI_MGMT
,
&
hdev
->
flags
);
...
...
@@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index)
memcpy
(
rp
.
name
,
hdev
->
dev_name
,
sizeof
(
hdev
->
dev_name
));
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
cmd_complete
(
sk
,
index
,
MGMT_OP_READ_INFO
,
&
rp
,
sizeof
(
rp
));
...
...
@@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
up
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
if
((
cp
->
val
&&
up
)
||
(
!
cp
->
val
&&
!
up
))
{
...
...
@@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
0
;
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
}
...
...
@@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
ENETDOWN
);
...
...
@@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
ENETDOWN
);
...
...
@@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
cp
->
val
)
set_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
);
...
...
@@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
err
=
mgmt_event
(
MGMT_EV_PAIRABLE
,
index
,
&
ev
,
sizeof
(
ev
),
sk
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
uuid
=
kmalloc
(
sizeof
(
*
uuid
),
GFP_ATOMIC
);
if
(
!
uuid
)
{
...
...
@@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
NULL
,
0
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
memcmp
(
cp
->
uuid
,
bt_uuid_any
,
16
)
==
0
)
{
err
=
hci_uuids_clear
(
hdev
);
...
...
@@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
NULL
,
0
);
unlock:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
hdev
->
major_class
=
cp
->
major
;
hdev
->
minor_class
=
cp
->
minor
;
...
...
@@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if
(
err
==
0
)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
NULL
,
0
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
BT_DBG
(
"hci%u enable %d"
,
index
,
cp
->
enable
);
...
...
@@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
NULL
,
0
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -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
;
int
i
,
err
;
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 %u bytes, got %u bytes"
,
len
,
expected_
len
);
if
(
expected_len
>
len
)
{
BT_ERR
(
"load_keys: expected
at least
%u bytes, got %u bytes"
,
expected_len
,
len
);
return
-
EINVAL
;
}
...
...
@@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG
(
"hci%u debug_keys %u key_count %u"
,
index
,
cp
->
debug_keys
,
key_count
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
hci_link_keys_clear
(
hdev
);
...
...
@@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
clear_bit
(
HCI_DEBUG_KEYS
,
&
hdev
->
flags
);
for
(
i
=
0
;
i
<
key_count
;
i
++
)
{
struct
mgmt_key_info
*
key
=
&
cp
->
keys
[
i
];
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
;
}
hci_add_link_key
(
hdev
,
NULL
,
0
,
&
key
->
bdaddr
,
key
->
val
,
key
->
type
,
key
->
pin_len
);
}
hci_dev_unlock
(
hdev
);
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_LOAD_KEYS
,
NULL
,
0
);
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
0
;
return
err
;
}
static
int
remove_key
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
...
...
@@ -971,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEY
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
err
=
hci_remove_link_key
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
{
...
...
@@ -994,7 +1013,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
}
unlock:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1020,7 +1039,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
ENETDOWN
);
...
...
@@ -1055,7 +1074,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1076,7 +1095,7 @@ static int get_connections(struct sock *sk, u16 index)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_GET_CONNECTIONS
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
count
=
0
;
list_for_each
(
p
,
&
hdev
->
conn_hash
.
list
)
{
...
...
@@ -1103,7 +1122,7 @@ static int get_connections(struct sock *sk, u16 index)
unlock:
kfree
(
rp
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
}
...
...
@@ -1149,7 +1168,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
ENETDOWN
);
...
...
@@ -1190,7 +1209,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1216,7 +1235,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
...
...
@@ -1227,7 +1246,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
err
=
send_pin_code_neg_reply
(
sk
,
index
,
hdev
,
cp
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1250,14 +1269,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
hdev
->
io_capability
=
cp
->
io_capability
;
BT_DBG
(
"%s IO capability set to 0x%02x"
,
hdev
->
name
,
hdev
->
io_capability
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
NULL
,
0
);
...
...
@@ -1343,7 +1362,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
cp
->
io_cap
==
0x03
)
{
sec_level
=
BT_SECURITY_MEDIUM
;
...
...
@@ -1385,7 +1404,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
0
;
unlock:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1417,7 +1436,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
mgmt_op
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
ENETDOWN
);
...
...
@@ -1435,7 +1454,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1459,7 +1478,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_SET_LOCAL_NAME
,
index
,
data
,
len
);
if
(
!
cmd
)
{
...
...
@@ -1474,7 +1493,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
failed:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1493,7 +1512,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
...
...
@@ -1523,7 +1542,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
mgmt_pending_remove
(
cmd
);
unlock:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1547,7 +1566,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
err
=
hci_add_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
,
cp
->
hash
,
cp
->
randomizer
);
...
...
@@ -1557,7 +1576,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
NULL
,
0
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1581,7 +1600,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
ENODEV
);
hci_dev_lock
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
err
=
hci_remove_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
...
...
@@ -1591,7 +1610,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
NULL
,
0
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
...
...
@@ -1958,17 +1977,28 @@ 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
;
struct
mgmt_ev_new_key
*
ev
;
int
err
,
total
;
memset
(
&
ev
,
0
,
sizeof
(
ev
));
total
=
sizeof
(
struct
mgmt_ev_new_key
)
+
key
->
dlen
;
ev
=
kzalloc
(
total
,
GFP_ATOMIC
);
if
(
!
ev
)
return
-
ENOMEM
;
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
;
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
;
return
mgmt_event
(
MGMT_EV_NEW_KEY
,
index
,
&
ev
,
sizeof
(
ev
),
NULL
);
memcpy
(
ev
->
key
.
data
,
key
->
data
,
key
->
dlen
);
err
=
mgmt_event
(
MGMT_EV_NEW_KEY
,
index
,
ev
,
total
,
NULL
);
kfree
(
ev
);
return
err
;
}
int
mgmt_connected
(
u16
index
,
bdaddr_t
*
bdaddr
)
...
...
net/bluetooth/sco.c
View file @
4b42c542
...
...
@@ -932,7 +932,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
if
(
conn
)
sco_conn_ready
(
conn
);
}
else
sco_conn_del
(
hcon
,
bt_
err
(
status
));
sco_conn_del
(
hcon
,
bt_
to_errno
(
status
));
return
0
;
}
...
...
@@ -944,7 +944,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
if
(
hcon
->
type
!=
SCO_LINK
&&
hcon
->
type
!=
ESCO_LINK
)
return
-
EINVAL
;
sco_conn_del
(
hcon
,
bt_
err
(
reason
));
sco_conn_del
(
hcon
,
bt_
to_errno
(
reason
));
return
0
;
}
...
...
net/bluetooth/smp.c
View file @
4b42c542
...
...
@@ -197,14 +197,34 @@ static __u8 seclevel_to_authreq(__u8 level)
}
static
void
build_pairing_cmd
(
struct
l2cap_conn
*
conn
,
struct
smp_cmd_pairing
*
cmd
,
__u8
authreq
)
struct
smp_cmd_pairing
*
req
,
struct
smp_cmd_pairing
*
rsp
,
__u8
authreq
)
{
cmd
->
io_capability
=
conn
->
hcon
->
io_capability
;
cmd
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
cmd
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
cmd
->
init_key_dist
=
0x00
;
cmd
->
resp_key_dist
=
0x00
;
cmd
->
auth_req
=
authreq
;
u8
dist_keys
;
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
;
authreq
|=
SMP_AUTH_BONDING
;
}
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
;
req
->
init_key_dist
=
dist_keys
;
req
->
resp_key_dist
=
dist_keys
;
req
->
auth_req
=
authreq
;
return
;
}
rsp
->
io_capability
=
conn
->
hcon
->
io_capability
;
rsp
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
rsp
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
rsp
->
init_key_dist
=
req
->
init_key_dist
&
dist_keys
;
rsp
->
resp_key_dist
=
req
->
resp_key_dist
&
dist_keys
;
rsp
->
auth_req
=
authreq
;
}
static
u8
check_enc_key_size
(
struct
l2cap_conn
*
conn
,
__u8
max_key_size
)
...
...
@@ -233,7 +253,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return
SMP_OOB_NOT_AVAIL
;
/* We didn't start the pairing, so no requirements */
build_pairing_cmd
(
conn
,
&
rsp
,
SMP_AUTH_NONE
);
build_pairing_cmd
(
conn
,
req
,
&
rsp
,
SMP_AUTH_NONE
);
key_size
=
min
(
req
->
max_key_size
,
rsp
.
max_key_size
);
if
(
check_enc_key_size
(
conn
,
key_size
))
...
...
@@ -347,8 +367,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
swap128
(
skb
->
data
,
random
);
skb_pull
(
skb
,
sizeof
(
random
));
memset
(
hcon
->
ltk
,
0
,
sizeof
(
hcon
->
ltk
));
if
(
conn
->
hcon
->
out
)
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
random
,
conn
->
preq
,
conn
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
...
...
@@ -370,29 +388,38 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
}
if
(
conn
->
hcon
->
out
)
{
u8
stk
[
16
],
rand
[
8
];
__le16
ediv
;
u8
rand
[
8
];
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
smp_s1
(
tfm
,
conn
->
tk
,
random
,
conn
->
prnd
,
key
);
swap128
(
key
,
hcon
->
l
tk
);
swap128
(
key
,
s
tk
);
memset
(
hcon
->
l
tk
+
conn
->
smp_key_size
,
0
,
memset
(
s
tk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
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
;
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
hci_le_start_enc
(
hcon
,
ediv
,
rand
,
hcon
->
ltk
);
}
else
{
u8
r
[
16
];
swap128
(
conn
->
prnd
,
r
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
r
),
r
);
smp_s1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
random
,
key
);
swap128
(
key
,
hcon
->
l
tk
);
swap128
(
key
,
s
tk
);
memset
(
hcon
->
l
tk
+
conn
->
smp_key_size
,
0
,
memset
(
s
tk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
hci_add_ltk
(
conn
->
hcon
->
hdev
,
0
,
conn
->
dst
,
conn
->
smp_key_size
,
ediv
,
rand
,
stk
);
}
return
0
;
...
...
@@ -412,7 +439,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull
(
skb
,
sizeof
(
*
rp
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
build_pairing_cmd
(
conn
,
&
cp
,
rp
->
auth_req
);
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
rp
->
auth_req
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
...
...
@@ -434,6 +461,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
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
;
...
...
@@ -450,8 +480,21 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
struct
smp_cmd_pairing
cp
;
struct
link_key
*
key
;
build_pairing_cmd
(
conn
,
&
cp
,
authreq
);
key
=
hci_find_link_key_type
(
hcon
->
hdev
,
conn
->
dst
,
HCI_LK_SMP_LTK
);
if
(
key
)
{
struct
key_master_id
*
master
=
(
void
*
)
key
->
data
;
hci_le_start_enc
(
hcon
,
master
->
ediv
,
master
->
rand
,
key
->
val
);
hcon
->
enc_key_size
=
key
->
pin_len
;
goto
done
;
}
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
authreq
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
...
...
@@ -465,18 +508,50 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
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
;
}
static
int
smp_cmd_encrypt_info
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_encrypt_info
*
rp
=
(
void
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
*
rp
));
memcpy
(
conn
->
tk
,
rp
->
ltk
,
sizeof
(
conn
->
tk
));
return
0
;
}
static
int
smp_cmd_master_ident
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_master_ident
*
rp
=
(
void
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
*
rp
));
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
src
,
conn
->
smp_key_size
,
rp
->
ediv
,
rp
->
rand
,
conn
->
tk
);
smp_distribute_keys
(
conn
,
1
);
return
0
;
}
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
__u8
code
=
skb
->
data
[
0
];
__u8
reason
;
int
err
=
0
;
if
(
!
lmp_host_le_capable
(
conn
->
hcon
->
hdev
))
{
err
=
-
ENOTSUPP
;
reason
=
SMP_PAIRING_NOTSUPP
;
goto
done
;
}
if
(
IS_ERR
(
conn
->
hcon
->
hdev
->
tfm
))
{
err
=
PTR_ERR
(
conn
->
hcon
->
hdev
->
tfm
);
reason
=
SMP_PAIRING_NOTSUPP
;
...
...
@@ -512,10 +587,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
break
;
case
SMP_CMD_ENCRYPT_INFO
:
reason
=
smp_cmd_encrypt_info
(
conn
,
skb
);
break
;
case
SMP_CMD_MASTER_IDENT
:
reason
=
smp_cmd_master_ident
(
conn
,
skb
);
break
;
case
SMP_CMD_IDENT_INFO
:
case
SMP_CMD_IDENT_ADDR_INFO
:
case
SMP_CMD_SIGN_INFO
:
/* Just ignored */
reason
=
0
;
break
;
default:
BT_DBG
(
"Unknown command code 0x%2.2x"
,
code
);
...
...
@@ -532,3 +617,86 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
kfree_skb
(
skb
);
return
err
;
}
int
smp_distribute_keys
(
struct
l2cap_conn
*
conn
,
__u8
force
)
{
struct
smp_cmd_pairing
*
req
,
*
rsp
;
__u8
*
keydist
;
BT_DBG
(
"conn %p force %d"
,
conn
,
force
);
if
(
IS_ERR
(
conn
->
hcon
->
hdev
->
tfm
))
return
PTR_ERR
(
conn
->
hcon
->
hdev
->
tfm
);
rsp
=
(
void
*
)
&
conn
->
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
];
if
(
conn
->
hcon
->
out
)
{
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
;
__le16
ediv
;
get_random_bytes
(
enc
.
ltk
,
sizeof
(
enc
.
ltk
));
get_random_bytes
(
&
ediv
,
sizeof
(
ediv
));
get_random_bytes
(
ident
.
rand
,
sizeof
(
ident
.
rand
));
smp_send_cmd
(
conn
,
SMP_CMD_ENCRYPT_INFO
,
sizeof
(
enc
),
&
enc
);
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
dst
,
conn
->
smp_key_size
,
ediv
,
ident
.
rand
,
enc
.
ltk
);
ident
.
ediv
=
cpu_to_le16
(
ediv
);
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
;
/* Send a dummy key */
get_random_bytes
(
idinfo
.
irk
,
sizeof
(
idinfo
.
irk
));
smp_send_cmd
(
conn
,
SMP_CMD_IDENT_INFO
,
sizeof
(
idinfo
),
&
idinfo
);
/* Just public address */
memset
(
&
addrinfo
,
0
,
sizeof
(
addrinfo
));
bacpy
(
&
addrinfo
.
bdaddr
,
conn
->
src
);
smp_send_cmd
(
conn
,
SMP_CMD_IDENT_ADDR_INFO
,
sizeof
(
addrinfo
),
&
addrinfo
);
*
keydist
&=
~
SMP_DIST_ID_KEY
;
}
if
(
*
keydist
&
SMP_DIST_SIGN
)
{
struct
smp_cmd_sign_info
sign
;
/* Send a dummy key */
get_random_bytes
(
sign
.
csrk
,
sizeof
(
sign
.
csrk
));
smp_send_cmd
(
conn
,
SMP_CMD_SIGN_INFO
,
sizeof
(
sign
),
&
sign
);
*
keydist
&=
~
SMP_DIST_SIGN
;
}
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