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
nexedi
linux
Commits
5f779bbd
Commit
5f779bbd
authored
Dec 06, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
parents
d7a4858c
5a13b095
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
880 additions
and
281 deletions
+880
-281
drivers/bluetooth/Kconfig
drivers/bluetooth/Kconfig
+3
-3
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btmrvl_sdio.c
+13
-2
drivers/bluetooth/btusb.c
drivers/bluetooth/btusb.c
+1
-2
drivers/bluetooth/hci_vhci.c
drivers/bluetooth/hci_vhci.c
+8
-0
include/net/bluetooth/bluetooth.h
include/net/bluetooth/bluetooth.h
+5
-0
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+38
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+20
-8
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+1
-1
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+45
-4
net/bluetooth/bnep/core.c
net/bluetooth/bnep/core.c
+3
-5
net/bluetooth/cmtp/core.c
net/bluetooth/cmtp/core.c
+3
-2
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+1
-1
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+12
-19
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+126
-26
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+66
-35
net/bluetooth/l2cap_sock.c
net/bluetooth/l2cap_sock.c
+13
-3
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+497
-163
net/bluetooth/smp.c
net/bluetooth/smp.c
+25
-7
No files found.
drivers/bluetooth/Kconfig
View file @
5f779bbd
...
...
@@ -188,7 +188,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support
Marvell Bluetooth devices, such as 8688/8787.
Marvell Bluetooth devices, such as 8688/8787
/8797
.
Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module.
...
...
@@ -201,8 +201,8 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth
devices with SDIO interface. Currently SD8688/SD8787
chipsets are
supported.
devices with SDIO interface. Currently SD8688/SD8787
/SD8797
chipsets are
supported.
Say Y here to compile support for Marvell BT-over-SDIO driver
into the kernel or say M to compile it as module.
...
...
drivers/bluetooth/btmrvl_sdio.c
View file @
5f779bbd
...
...
@@ -65,7 +65,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
.
io_port_1
=
0x01
,
.
io_port_2
=
0x02
,
};
static
const
struct
btmrvl_sdio_card_reg
btmrvl_reg_87
87
=
{
static
const
struct
btmrvl_sdio_card_reg
btmrvl_reg_87
xx
=
{
.
cfg
=
0x00
,
.
host_int_mask
=
0x02
,
.
host_intstatus
=
0x03
,
...
...
@@ -92,7 +92,14 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
static
const
struct
btmrvl_sdio_device
btmrvl_sdio_sd8787
=
{
.
helper
=
NULL
,
.
firmware
=
"mrvl/sd8787_uapsta.bin"
,
.
reg
=
&
btmrvl_reg_8787
,
.
reg
=
&
btmrvl_reg_87xx
,
.
sd_blksz_fw_dl
=
256
,
};
static
const
struct
btmrvl_sdio_device
btmrvl_sdio_sd8797
=
{
.
helper
=
NULL
,
.
firmware
=
"mrvl/sd8797_uapsta.bin"
,
.
reg
=
&
btmrvl_reg_87xx
,
.
sd_blksz_fw_dl
=
256
,
};
...
...
@@ -103,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8787 Bluetooth device */
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_MARVELL
,
0x911A
),
.
driver_data
=
(
unsigned
long
)
&
btmrvl_sdio_sd8787
},
/* Marvell SD8797 Bluetooth device */
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_MARVELL
,
0x912A
),
.
driver_data
=
(
unsigned
long
)
&
btmrvl_sdio_sd8797
},
{
}
/* Terminating entry */
};
...
...
@@ -1076,3 +1086,4 @@ MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE
(
"sd8688_helper.bin"
);
MODULE_FIRMWARE
(
"sd8688.bin"
);
MODULE_FIRMWARE
(
"mrvl/sd8787_uapsta.bin"
);
MODULE_FIRMWARE
(
"mrvl/sd8797_uapsta.bin"
);
drivers/bluetooth/btusb.c
View file @
5f779bbd
...
...
@@ -785,9 +785,8 @@ static int btusb_send_frame(struct sk_buff *skb)
usb_mark_last_busy
(
data
->
udev
);
}
usb_free_urb
(
urb
);
done:
usb_free_urb
(
urb
);
return
err
;
}
...
...
drivers/bluetooth/hci_vhci.c
View file @
5f779bbd
...
...
@@ -41,6 +41,8 @@
#define VERSION "1.3"
static
bool
amp
;
struct
vhci_data
{
struct
hci_dev
*
hdev
;
...
...
@@ -239,6 +241,9 @@ static int vhci_open(struct inode *inode, struct file *file)
hdev
->
bus
=
HCI_VIRTUAL
;
hdev
->
driver_data
=
data
;
if
(
amp
)
hdev
->
dev_type
=
HCI_AMP
;
hdev
->
open
=
vhci_open_dev
;
hdev
->
close
=
vhci_close_dev
;
hdev
->
flush
=
vhci_flush
;
...
...
@@ -303,6 +308,9 @@ static void __exit vhci_exit(void)
module_init
(
vhci_init
);
module_exit
(
vhci_exit
);
module_param
(
amp
,
bool
,
0644
);
MODULE_PARM_DESC
(
amp
,
"Create AMP controller device"
);
MODULE_AUTHOR
(
"Marcel Holtmann <marcel@holtmann.org>"
);
MODULE_DESCRIPTION
(
"Bluetooth virtual HCI driver ver "
VERSION
);
MODULE_VERSION
(
VERSION
);
...
...
include/net/bluetooth/bluetooth.h
View file @
5f779bbd
...
...
@@ -36,6 +36,11 @@
#define PF_BLUETOOTH AF_BLUETOOTH
#endif
/* Bluetooth versions */
#define BLUETOOTH_VER_1_1 1
#define BLUETOOTH_VER_1_2 2
#define BLUETOOTH_VER_2_0 3
/* Reserv for core and drivers use */
#define BT_SKB_RESERVE 8
...
...
include/net/bluetooth/hci.h
View file @
5f779bbd
...
...
@@ -88,6 +88,14 @@ enum {
HCI_RESET
,
};
/*
* BR/EDR and/or LE controller flags: the flags defined here should represent
* states from the controller.
*/
enum
{
HCI_LE_SCAN
,
};
/* HCI ioctl defines */
#define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int)
...
...
@@ -453,6 +461,14 @@ struct hci_rp_user_confirm_reply {
#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d
#define HCI_OP_USER_PASSKEY_REPLY 0x042e
struct
hci_cp_user_passkey_reply
{
bdaddr_t
bdaddr
;
__le32
passkey
;
}
__packed
;
#define HCI_OP_USER_PASSKEY_NEG_REPLY 0x042f
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
struct
hci_cp_remote_oob_data_reply
{
bdaddr_t
bdaddr
;
...
...
@@ -669,6 +685,12 @@ struct hci_rp_read_local_oob_data {
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
struct
hci_rp_read_flow_control_mode
{
__u8
status
;
__u8
mode
;
}
__packed
;
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
struct
hci_cp_write_le_host_supported
{
__u8
le
;
...
...
@@ -760,6 +782,15 @@ struct hci_rp_le_read_buffer_size {
__u8
le_max_pkt
;
}
__packed
;
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
struct
hci_cp_le_set_scan_param
{
__u8
type
;
__le16
interval
;
__le16
window
;
__u8
own_address_type
;
__u8
filter_policy
;
}
__packed
;
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct
hci_cp_le_set_scan_enable
{
__u8
enable
;
...
...
@@ -1076,6 +1107,11 @@ struct hci_ev_user_confirm_req {
__le32
passkey
;
}
__packed
;
#define HCI_EV_USER_PASSKEY_REQUEST 0x34
struct
hci_ev_user_passkey_req
{
bdaddr_t
bdaddr
;
}
__packed
;
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
struct
hci_ev_remote_oob_data_request
{
bdaddr_t
bdaddr
;
...
...
@@ -1331,4 +1367,6 @@ struct hci_inquiry_req {
};
#define IREQ_CACHE_FLUSH 0x0001
extern
int
enable_hs
;
#endif
/* __HCI_H */
include/net/bluetooth/hci_core.h
View file @
5f779bbd
...
...
@@ -170,6 +170,8 @@ struct hci_dev {
__u32
amp_max_flush_to
;
__u32
amp_be_flush_to
;
__u8
flow_ctl_mode
;
unsigned
int
auto_accept_delay
;
unsigned
long
quirks
;
...
...
@@ -250,6 +252,8 @@ struct hci_dev {
struct
module
*
owner
;
unsigned
long
dev_flags
;
int
(
*
open
)(
struct
hci_dev
*
hdev
);
int
(
*
close
)(
struct
hci_dev
*
hdev
);
int
(
*
flush
)(
struct
hci_dev
*
hdev
);
...
...
@@ -917,11 +921,13 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
int
mgmt_write_scan_failed
(
struct
hci_dev
*
hdev
,
u8
scan
,
u8
status
);
int
mgmt_new_link_key
(
struct
hci_dev
*
hdev
,
struct
link_key
*
key
,
u8
persistent
);
int
mgmt_connected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
);
int
mgmt_disconnected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
);
int
mgmt_disconnect_failed
(
struct
hci_dev
*
hdev
);
int
mgmt_connect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
,
u8
status
);
int
mgmt_connected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
,
u8
addr_type
);
int
mgmt_disconnected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
,
u8
addr_type
);
int
mgmt_disconnect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
int
mgmt_connect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
,
u8
addr_type
,
u8
status
);
int
mgmt_pin_code_request
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
secure
);
int
mgmt_pin_code_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
...
...
@@ -933,14 +939,20 @@ int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8
status
);
int
mgmt_user_confirm_neg_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
int
mgmt_user_passkey_request
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
mgmt_user_passkey_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
int
mgmt_user_passkey_neg_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
int
mgmt_auth_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
);
int
mgmt_set_local_name_complete
(
struct
hci_dev
*
hdev
,
u8
*
name
,
u8
status
);
int
mgmt_read_local_oob_data_reply_complete
(
struct
hci_dev
*
hdev
,
u8
*
hash
,
u8
*
randomizer
,
u8
status
);
int
mgmt_device_found
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
,
u8
*
dev_class
,
s8
rssi
,
u8
*
eir
);
int
mgmt_device_found
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_
type
,
u8
addr_type
,
u8
*
dev_class
,
s8
rssi
,
u8
*
eir
);
int
mgmt_remote_name
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
*
name
);
int
mgmt_inquiry_failed
(
struct
hci_dev
*
hdev
,
u8
status
);
int
mgmt_start_discovery_failed
(
struct
hci_dev
*
hdev
,
u8
status
);
int
mgmt_stop_discovery_failed
(
struct
hci_dev
*
hdev
,
u8
status
);
int
mgmt_discovering
(
struct
hci_dev
*
hdev
,
u8
discovering
);
int
mgmt_device_blocked
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
mgmt_device_unblocked
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
...
...
include/net/bluetooth/l2cap.h
View file @
5f779bbd
...
...
@@ -792,7 +792,6 @@ static inline __u8 __ctrl_size(struct l2cap_chan *chan)
}
extern
int
disable_ertm
;
extern
int
enable_hs
;
int
l2cap_init_sockets
(
void
);
void
l2cap_cleanup_sockets
(
void
);
...
...
@@ -810,5 +809,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan);
int
l2cap_chan_send
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
,
u32
priority
);
void
l2cap_chan_busy
(
struct
l2cap_chan
*
chan
,
int
busy
);
int
l2cap_chan_check_security
(
struct
l2cap_chan
*
chan
);
#endif
/* __L2CAP_H */
include/net/bluetooth/mgmt.h
View file @
5f779bbd
...
...
@@ -23,6 +23,23 @@
#define MGMT_INDEX_NONE 0xFFFF
#define MGMT_STATUS_SUCCESS 0x00
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
#define MGMT_STATUS_NOT_CONNECTED 0x02
#define MGMT_STATUS_FAILED 0x03
#define MGMT_STATUS_CONNECT_FAILED 0x04
#define MGMT_STATUS_AUTH_FAILED 0x05
#define MGMT_STATUS_NOT_PAIRED 0x06
#define MGMT_STATUS_NO_RESOURCES 0x07
#define MGMT_STATUS_TIMEOUT 0x08
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
#define MGMT_STATUS_BUSY 0x0a
#define MGMT_STATUS_REJECTED 0x0b
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
#define MGMT_STATUS_INVALID_PARAMS 0x0d
#define MGMT_STATUS_DISCONNECTED 0x0e
#define MGMT_STATUS_NOT_POWERED 0x0f
struct
mgmt_hdr
{
__le16
opcode
;
__le16
index
;
...
...
@@ -119,6 +136,10 @@ struct mgmt_cp_remove_keys {
bdaddr_t
bdaddr
;
__u8
disconnect
;
}
__packed
;
struct
mgmt_rp_remove_keys
{
bdaddr_t
bdaddr
;
__u8
status
;
};
#define MGMT_OP_DISCONNECT 0x000F
struct
mgmt_cp_disconnect
{
...
...
@@ -126,11 +147,12 @@ struct mgmt_cp_disconnect {
}
__packed
;
struct
mgmt_rp_disconnect
{
bdaddr_t
bdaddr
;
__u8
status
;
}
__packed
;
#define MGMT_ADDR_BREDR 0x00
#define MGMT_ADDR_LE
0x01
#define MGMT_ADDR_
BREDR_LE
0x02
#define MGMT_ADDR_LE
_PUBLIC
0x01
#define MGMT_ADDR_
LE_RANDOM
0x02
#define MGMT_ADDR_INVALID 0xff
struct
mgmt_addr_info
{
...
...
@@ -167,11 +189,11 @@ struct mgmt_cp_set_io_capability {
#define MGMT_OP_PAIR_DEVICE 0x0014
struct
mgmt_cp_pair_device
{
bdaddr_t
bd
addr
;
struct
mgmt_addr_info
addr
;
__u8
io_cap
;
}
__packed
;
struct
mgmt_rp_pair_device
{
bdaddr_t
bd
addr
;
struct
mgmt_addr_info
addr
;
__u8
status
;
}
__packed
;
...
...
@@ -210,6 +232,9 @@ struct mgmt_cp_remove_remote_oob_data {
}
__packed
;
#define MGMT_OP_START_DISCOVERY 0x001B
struct
mgmt_cp_start_discovery
{
__u8
type
;
}
__packed
;
#define MGMT_OP_STOP_DISCOVERY 0x001C
...
...
@@ -228,6 +253,17 @@ struct mgmt_cp_set_fast_connectable {
__u8
enable
;
}
__packed
;
#define MGMT_OP_USER_PASSKEY_REPLY 0x0020
struct
mgmt_cp_user_passkey_reply
{
bdaddr_t
bdaddr
;
__le32
passkey
;
}
__packed
;
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x0021
struct
mgmt_cp_user_passkey_neg_reply
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct
mgmt_ev_cmd_complete
{
__le16
opcode
;
...
...
@@ -322,3 +358,8 @@ struct mgmt_ev_device_blocked {
struct
mgmt_ev_device_unblocked
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0017
struct
mgmt_ev_user_passkey_request
{
bdaddr_t
bdaddr
;
}
__packed
;
net/bluetooth/bnep/core.c
View file @
5f779bbd
...
...
@@ -77,17 +77,12 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
static
void
__bnep_link_session
(
struct
bnep_session
*
s
)
{
/* It's safe to call __module_get() here because sessions are added
by the socket layer which has to hold the reference to this module.
*/
__module_get
(
THIS_MODULE
);
list_add
(
&
s
->
list
,
&
bnep_session_list
);
}
static
void
__bnep_unlink_session
(
struct
bnep_session
*
s
)
{
list_del
(
&
s
->
list
);
module_put
(
THIS_MODULE
);
}
static
int
bnep_send
(
struct
bnep_session
*
s
,
void
*
data
,
size_t
len
)
...
...
@@ -528,6 +523,7 @@ static int bnep_session(void *arg)
up_write
(
&
bnep_session_sem
);
free_netdev
(
dev
);
module_put_and_exit
(
0
);
return
0
;
}
...
...
@@ -614,9 +610,11 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
__bnep_link_session
(
s
);
__module_get
(
THIS_MODULE
);
s
->
task
=
kthread_run
(
bnep_session
,
s
,
"kbnepd %s"
,
dev
->
name
);
if
(
IS_ERR
(
s
->
task
))
{
/* Session thread start failed, gotta cleanup. */
module_put
(
THIS_MODULE
);
unregister_netdev
(
dev
);
__bnep_unlink_session
(
s
);
err
=
PTR_ERR
(
s
->
task
);
...
...
net/bluetooth/cmtp/core.c
View file @
5f779bbd
...
...
@@ -65,14 +65,12 @@ static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
static
void
__cmtp_link_session
(
struct
cmtp_session
*
session
)
{
__module_get
(
THIS_MODULE
);
list_add
(
&
session
->
list
,
&
cmtp_session_list
);
}
static
void
__cmtp_unlink_session
(
struct
cmtp_session
*
session
)
{
list_del
(
&
session
->
list
);
module_put
(
THIS_MODULE
);
}
static
void
__cmtp_copy_session
(
struct
cmtp_session
*
session
,
struct
cmtp_conninfo
*
ci
)
...
...
@@ -325,6 +323,7 @@ static int cmtp_session(void *arg)
up_write
(
&
cmtp_session_sem
);
kfree
(
session
);
module_put_and_exit
(
0
);
return
0
;
}
...
...
@@ -374,9 +373,11 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
__cmtp_link_session
(
session
);
__module_get
(
THIS_MODULE
);
session
->
task
=
kthread_run
(
cmtp_session
,
session
,
"kcmtpd_ctr_%d"
,
session
->
num
);
if
(
IS_ERR
(
session
->
task
))
{
module_put
(
THIS_MODULE
);
err
=
PTR_ERR
(
session
->
task
);
goto
unlink
;
}
...
...
net/bluetooth/hci_conn.c
View file @
5f779bbd
...
...
@@ -123,7 +123,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
BT_DBG
(
"%p"
,
conn
);
if
(
conn
->
hdev
->
hci_ver
<
2
)
if
(
conn
->
hdev
->
hci_ver
<
BLUETOOTH_VER_1_
2
)
return
;
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
...
...
net/bluetooth/hci_core.c
View file @
5f779bbd
...
...
@@ -54,6 +54,8 @@
#define AUTO_OFF_TIMEOUT 2000
int
enable_hs
;
static
void
hci_cmd_task
(
unsigned
long
arg
);
static
void
hci_rx_task
(
unsigned
long
arg
);
static
void
hci_tx_task
(
unsigned
long
arg
);
...
...
@@ -228,18 +230,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_send_cmd
(
hdev
,
HCI_OP_READ_BUFFER_SIZE
,
0
,
NULL
);
#if 0
/* Host buffer size */
{
struct hci_cp_host_buffer_size cp;
cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
cp.sco_mtu = HCI_MAX_SCO_SIZE;
cp.acl_max_pkt = cpu_to_le16(0xffff);
cp.sco_max_pkt = cpu_to_le16(0xffff);
hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
}
#endif
/* Read BD Address */
hci_send_cmd
(
hdev
,
HCI_OP_READ_BD_ADDR
,
0
,
NULL
);
...
...
@@ -521,8 +511,9 @@ int hci_dev_open(__u16 dev)
if
(
test_bit
(
HCI_QUIRK_RAW_DEVICE
,
&
hdev
->
quirks
))
set_bit
(
HCI_RAW
,
&
hdev
->
flags
);
/* Treat all non BR/EDR controllers as raw devices for now */
if
(
hdev
->
dev_type
!=
HCI_BREDR
)
/* Treat all non BR/EDR controllers as raw devices if
enable_hs is not set */
if
(
hdev
->
dev_type
!=
HCI_BREDR
&&
!
enable_hs
)
set_bit
(
HCI_RAW
,
&
hdev
->
flags
);
if
(
hdev
->
open
(
hdev
))
{
...
...
@@ -1336,14 +1327,12 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct
bdaddr_list
*
entry
;
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
{
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
return
hci_blacklist_clear
(
hdev
);
}
entry
=
hci_blacklist_lookup
(
hdev
,
bdaddr
);
if
(
!
entry
)
{
if
(
!
entry
)
return
-
ENOENT
;
}
list_del
(
&
entry
->
list
);
kfree
(
entry
);
...
...
@@ -1451,12 +1440,13 @@ int hci_register_dev(struct hci_dev *hdev)
sprintf
(
hdev
->
name
,
"hci%d"
,
id
);
hdev
->
id
=
id
;
list_add
(
&
hdev
->
list
,
head
);
list_add
_tail
(
&
hdev
->
list
,
head
);
atomic_set
(
&
hdev
->
refcnt
,
1
);
spin_lock_init
(
&
hdev
->
lock
);
hdev
->
flags
=
0
;
hdev
->
dev_flags
=
0
;
hdev
->
pkt_type
=
(
HCI_DM1
|
HCI_DH1
|
HCI_HV1
);
hdev
->
esco_type
=
(
ESCO_HV1
);
hdev
->
link_mode
=
(
HCI_LM_ACCEPT
);
...
...
@@ -2614,3 +2604,6 @@ int hci_cancel_inquiry(struct hci_dev *hdev)
return
hci_send_cmd
(
hdev
,
HCI_OP_INQUIRY_CANCEL
,
0
,
NULL
);
}
module_param
(
enable_hs
,
bool
,
0644
);
MODULE_PARM_DESC
(
enable_hs
,
"Enable High Speed"
);
net/bluetooth/hci_event.c
View file @
5f779bbd
...
...
@@ -55,8 +55,12 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
if
(
status
)
{
hci_dev_lock
(
hdev
);
mgmt_stop_discovery_failed
(
hdev
,
status
);
hci_dev_unlock
(
hdev
);
return
;
}
clear_bit
(
HCI_INQUIRY
,
&
hdev
->
flags
);
...
...
@@ -190,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit
(
HCI_RESET
,
&
hdev
->
flags
);
hci_req_complete
(
hdev
,
HCI_OP_RESET
,
status
);
hdev
->
dev_flags
=
0
;
}
static
void
hci_cc_write_local_name
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -494,7 +500,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
* any event mask for pre 1.2 devices */
if
(
hdev
->
lmp_ver
<=
1
)
if
(
hdev
->
hci_ver
<
BLUETOOTH_VER_1_2
)
return
;
events
[
4
]
|=
0x01
;
/* Flow Specification Complete */
...
...
@@ -558,7 +564,7 @@ static void hci_setup(struct hci_dev *hdev)
{
hci_setup_event_mask
(
hdev
);
if
(
hdev
->
lmp_ver
>
1
)
if
(
hdev
->
hci_ver
>
BLUETOOTH_VER_1_
1
)
hci_send_cmd
(
hdev
,
HCI_OP_READ_LOCAL_COMMANDS
,
0
,
NULL
);
if
(
hdev
->
features
[
6
]
&
LMP_SIMPLE_PAIR
)
{
...
...
@@ -713,6 +719,21 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
hci_req_complete
(
hdev
,
HCI_OP_READ_LOCAL_EXT_FEATURES
,
rp
->
status
);
}
static
void
hci_cc_read_flow_control_mode
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_flow_control_mode
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hdev
->
flow_ctl_mode
=
rp
->
mode
;
hci_req_complete
(
hdev
,
HCI_OP_READ_FLOW_CONTROL_MODE
,
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
;
...
...
@@ -927,6 +948,37 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_user_passkey_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_user_confirm_reply
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
hci_dev_lock
(
hdev
);
if
(
test_bit
(
HCI_MGMT
,
&
hdev
->
flags
))
mgmt_user_passkey_reply_complete
(
hdev
,
&
rp
->
bdaddr
,
rp
->
status
);
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_user_passkey_neg_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_user_confirm_reply
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
hci_dev_lock
(
hdev
);
if
(
test_bit
(
HCI_MGMT
,
&
hdev
->
flags
))
mgmt_user_passkey_neg_reply_complete
(
hdev
,
&
rp
->
bdaddr
,
rp
->
status
);
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_read_local_oob_data_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
...
...
@@ -940,6 +992,13 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_le_set_scan_param
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
}
static
void
hci_cc_le_set_scan_enable
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
...
...
@@ -956,12 +1015,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
return
;
if
(
cp
->
enable
==
0x01
)
{
set_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
del_timer
(
&
hdev
->
adv_timer
);
hci_dev_lock
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_dev_unlock
(
hdev
);
}
else
if
(
cp
->
enable
==
0x00
)
{
clear_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
mod_timer
(
&
hdev
->
adv_timer
,
jiffies
+
ADV_CLEAR_TIMEOUT
);
}
}
...
...
@@ -1014,7 +1077,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
hci_conn_check_pending
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
test_bit
(
HCI_MGMT
,
&
hdev
->
flags
))
mgmt_
inqui
ry_failed
(
hdev
,
status
);
mgmt_
start_discove
ry_failed
(
hdev
,
status
);
hci_dev_unlock
(
hdev
);
return
;
}
...
...
@@ -1437,7 +1500,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
data
.
rssi
=
0x00
;
data
.
ssp_mode
=
0x00
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
0x00
,
info
->
dev_class
,
0
,
NULL
);
}
...
...
@@ -1472,7 +1535,8 @@ 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
,
&
ev
->
bdaddr
,
conn
->
type
);
mgmt_connected
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
,
conn
->
dst_type
);
}
else
conn
->
state
=
BT_CONNECTED
;
...
...
@@ -1494,7 +1558,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
}
/* Set packet type for incoming connection */
if
(
!
conn
->
out
&&
hdev
->
hci_ver
<
3
)
{
if
(
!
conn
->
out
&&
hdev
->
hci_ver
<
BLUETOOTH_VER_2_0
)
{
struct
hci_cp_change_conn_ptype
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt_type
);
...
...
@@ -1505,7 +1569,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn
->
state
=
BT_CLOSED
;
if
(
conn
->
type
==
ACL_LINK
)
mgmt_connect_failed
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
,
ev
->
status
);
conn
->
dst_type
,
ev
->
status
);
}
if
(
conn
->
type
==
ACL_LINK
)
...
...
@@ -1604,26 +1668,27 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG
(
"%s status %d"
,
hdev
->
name
,
ev
->
status
);
if
(
ev
->
status
)
{
hci_dev_lock
(
hdev
);
mgmt_disconnect_failed
(
hdev
);
hci_dev_unlock
(
hdev
);
return
;
}
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
!
conn
)
goto
unlock
;
if
(
ev
->
status
==
0
)
conn
->
state
=
BT_CLOSED
;
if
(
conn
->
type
==
ACL_LINK
||
conn
->
type
==
LE_LINK
)
mgmt_disconnected
(
hdev
,
&
conn
->
dst
,
conn
->
type
);
if
(
conn
->
type
==
ACL_LINK
||
conn
->
type
==
LE_LINK
)
{
if
(
ev
->
status
!=
0
)
mgmt_disconnect_failed
(
hdev
,
&
conn
->
dst
,
ev
->
status
);
else
mgmt_disconnected
(
hdev
,
&
conn
->
dst
,
conn
->
type
,
conn
->
dst_type
);
}
if
(
ev
->
status
==
0
)
{
hci_proto_disconn_cfm
(
conn
,
ev
->
reason
);
hci_conn_del
(
conn
);
}
unlock:
hci_dev_unlock
(
hdev
);
...
...
@@ -1961,6 +2026,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_write_ca_timeout
(
hdev
,
skb
);
break
;
case
HCI_OP_READ_FLOW_CONTROL_MODE
:
hci_cc_read_flow_control_mode
(
hdev
,
skb
);
break
;
case
HCI_OP_READ_LOCAL_AMP_INFO
:
hci_cc_read_local_amp_info
(
hdev
,
skb
);
break
;
...
...
@@ -2009,6 +2078,17 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_user_confirm_neg_reply
(
hdev
,
skb
);
break
;
case
HCI_OP_USER_PASSKEY_REPLY
:
hci_cc_user_passkey_reply
(
hdev
,
skb
);
break
;
case
HCI_OP_USER_PASSKEY_NEG_REPLY
:
hci_cc_user_passkey_neg_reply
(
hdev
,
skb
);
case
HCI_OP_LE_SET_SCAN_PARAM
:
hci_cc_le_set_scan_param
(
hdev
,
skb
);
break
;
case
HCI_OP_LE_SET_SCAN_ENABLE
:
hci_cc_le_set_scan_enable
(
hdev
,
skb
);
break
;
...
...
@@ -2096,7 +2176,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
case
HCI_OP_DISCONNECT
:
if
(
ev
->
status
!=
0
)
mgmt_disconnect_failed
(
hdev
);
mgmt_disconnect_failed
(
hdev
,
NULL
,
ev
->
status
);
break
;
case
HCI_OP_LE_CREATE_CONN
:
...
...
@@ -2444,7 +2524,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x00
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
0x00
,
info
->
dev_class
,
info
->
rssi
,
NULL
);
}
...
...
@@ -2461,7 +2541,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x00
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
0x00
,
info
->
dev_class
,
info
->
rssi
,
NULL
);
}
...
...
@@ -2604,7 +2684,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x01
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
mgmt_device_found
(
hdev
,
&
info
->
bdaddr
,
ACL_LINK
,
0x00
,
info
->
dev_class
,
info
->
rssi
,
info
->
data
);
}
...
...
@@ -2768,6 +2848,21 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_user_passkey_request_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_user_passkey_req
*
ev
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
(
hdev
);
if
(
test_bit
(
HCI_MGMT
,
&
hdev
->
flags
))
mgmt_user_passkey_request
(
hdev
,
&
ev
->
bdaddr
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_simple_pair_complete_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_simple_pair_complete
*
ev
=
(
void
*
)
skb
->
data
;
...
...
@@ -2868,14 +2963,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
}
if
(
ev
->
status
)
{
mgmt_connect_failed
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
,
ev
->
status
);
mgmt_connect_failed
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
,
conn
->
dst_type
,
ev
->
status
);
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
conn
->
state
=
BT_CLOSED
;
hci_conn_del
(
conn
);
goto
unlock
;
}
mgmt_connected
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
);
mgmt_connected
(
hdev
,
&
ev
->
bdaddr
,
conn
->
type
,
conn
->
dst_type
);
conn
->
sec_level
=
BT_SECURITY_LOW
;
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
...
...
@@ -3106,6 +3202,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_user_confirm_request_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_USER_PASSKEY_REQUEST
:
hci_user_passkey_request_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_SIMPLE_PAIR_COMPLETE
:
hci_simple_pair_complete_evt
(
hdev
,
skb
);
break
;
...
...
net/bluetooth/l2cap_core.c
View file @
5f779bbd
...
...
@@ -57,7 +57,6 @@
#include <net/bluetooth/smp.h>
int
disable_ertm
;
int
enable_hs
;
static
u32
l2cap_feat_mask
=
L2CAP_FEAT_FIXED_CHAN
;
static
u8
l2cap_fixed_chan
[
8
]
=
{
L2CAP_FC_L2CAP
,
};
...
...
@@ -97,7 +96,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
return
c
;
}
return
NULL
;
}
static
struct
l2cap_chan
*
__l2cap_get_chan_by_scid
(
struct
l2cap_conn
*
conn
,
u16
cid
)
...
...
@@ -154,12 +152,9 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
list_for_each_entry
(
c
,
&
chan_list
,
global_l
)
{
if
(
c
->
sport
==
psm
&&
!
bacmp
(
&
bt_sk
(
c
->
sk
)
->
src
,
src
))
goto
found
;
}
c
=
NULL
;
found:
return
c
;
}
return
NULL
;
}
int
l2cap_add_psm
(
struct
l2cap_chan
*
chan
,
bdaddr_t
*
src
,
__le16
psm
)
...
...
@@ -234,8 +229,37 @@ static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
chan_put
(
chan
);
}
static
char
*
state_to_string
(
int
state
)
{
switch
(
state
)
{
case
BT_CONNECTED
:
return
"BT_CONNECTED"
;
case
BT_OPEN
:
return
"BT_OPEN"
;
case
BT_BOUND
:
return
"BT_BOUND"
;
case
BT_LISTEN
:
return
"BT_LISTEN"
;
case
BT_CONNECT
:
return
"BT_CONNECT"
;
case
BT_CONNECT2
:
return
"BT_CONNECT2"
;
case
BT_CONFIG
:
return
"BT_CONFIG"
;
case
BT_DISCONN
:
return
"BT_DISCONN"
;
case
BT_CLOSED
:
return
"BT_CLOSED"
;
}
return
"invalid state"
;
}
static
void
l2cap_state_change
(
struct
l2cap_chan
*
chan
,
int
state
)
{
BT_DBG
(
"%p %s -> %s"
,
chan
,
state_to_string
(
chan
->
state
),
state_to_string
(
state
));
chan
->
state
=
state
;
chan
->
ops
->
state_change
(
chan
->
data
,
state
);
}
...
...
@@ -518,7 +542,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
}
/* Service level security */
static
inline
int
l2cap
_check_security
(
struct
l2cap_chan
*
chan
)
int
l2cap_chan
_check_security
(
struct
l2cap_chan
*
chan
)
{
struct
l2cap_conn
*
conn
=
chan
->
conn
;
__u8
auth_type
;
...
...
@@ -664,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
if
(
!
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_DONE
))
return
;
if
(
l2cap_check_security
(
chan
)
&&
if
(
l2cap_ch
an_ch
eck_security
(
chan
)
&&
__l2cap_no_conn_pending
(
chan
))
{
struct
l2cap_conn_req
req
;
req
.
scid
=
cpu_to_le16
(
chan
->
scid
);
...
...
@@ -754,7 +778,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
if
(
chan
->
state
==
BT_CONNECT
)
{
struct
l2cap_conn_req
req
;
if
(
!
l2cap_check_security
(
chan
)
||
if
(
!
l2cap_ch
an_ch
eck_security
(
chan
)
||
!
__l2cap_no_conn_pending
(
chan
))
{
bh_unlock_sock
(
sk
);
continue
;
...
...
@@ -787,7 +811,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
rsp
.
scid
=
cpu_to_le16
(
chan
->
dcid
);
rsp
.
dcid
=
cpu_to_le16
(
chan
->
scid
);
if
(
l2cap_check_security
(
chan
))
{
if
(
l2cap_ch
an_ch
eck_security
(
chan
))
{
if
(
bt_sk
(
sk
)
->
defer_setup
)
{
struct
sock
*
parent
=
bt_sk
(
sk
)
->
parent
;
rsp
.
result
=
cpu_to_le16
(
L2CAP_CR_PEND
);
...
...
@@ -1181,7 +1205,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
if
(
hcon
->
state
==
BT_CONNECTED
)
{
if
(
chan
->
chan_type
!=
L2CAP_CHAN_CONN_ORIENTED
)
{
__clear_chan_timer
(
chan
);
if
(
l2cap_check_security
(
chan
))
if
(
l2cap_ch
an_ch
eck_security
(
chan
))
l2cap_state_change
(
chan
,
BT_CONNECTED
);
}
else
l2cap_do_start
(
chan
);
...
...
@@ -1318,14 +1342,12 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
if
(
!
skb
)
return
;
do
{
if
(
bt_cb
(
skb
)
->
tx_seq
==
tx_seq
)
break
;
while
(
bt_cb
(
skb
)
->
tx_seq
!=
tx_seq
)
{
if
(
skb_queue_is_last
(
&
chan
->
tx_q
,
skb
))
return
;
}
while
((
skb
=
skb_queue_next
(
&
chan
->
tx_q
,
skb
)));
skb
=
skb_queue_next
(
&
chan
->
tx_q
,
skb
);
}
if
(
chan
->
remote_max_tx
&&
bt_cb
(
skb
)
->
retries
==
chan
->
remote_max_tx
)
{
...
...
@@ -1906,7 +1928,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
{
struct
l2cap_conf_efs
efs
;
switch
(
chan
->
mode
)
{
switch
(
chan
->
mode
)
{
case
L2CAP_MODE_ERTM
:
efs
.
id
=
chan
->
local_id
;
efs
.
stype
=
chan
->
local_stype
;
...
...
@@ -2606,7 +2628,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
chan
->
ident
=
cmd
->
ident
;
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_DONE
)
{
if
(
l2cap_check_security
(
chan
))
{
if
(
l2cap_ch
an_ch
eck_security
(
chan
))
{
if
(
bt_sk
(
sk
)
->
defer_setup
)
{
l2cap_state_change
(
chan
,
BT_CONNECT2
);
result
=
L2CAP_CR_PEND
;
...
...
@@ -3019,7 +3041,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if
(
sock_owned_by_user
(
sk
))
{
l2cap_state_change
(
chan
,
BT_DISCONN
);
l2cap_state_change
(
chan
,
BT_DISCONN
);
__clear_chan_timer
(
chan
);
__set_chan_timer
(
chan
,
L2CAP_DISC_TIMEOUT
);
bh_unlock_sock
(
sk
);
...
...
@@ -3562,14 +3584,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
bt_cb
(
skb
)
->
sar
=
sar
;
next_skb
=
skb_peek
(
&
chan
->
srej_q
);
if
(
!
next_skb
)
{
__skb_queue_tail
(
&
chan
->
srej_q
,
skb
);
return
0
;
}
tx_seq_offset
=
__seq_offset
(
chan
,
tx_seq
,
chan
->
buffer_seq
);
do
{
while
(
next_skb
)
{
if
(
bt_cb
(
next_skb
)
->
tx_seq
==
tx_seq
)
return
-
EINVAL
;
...
...
@@ -3582,9 +3600,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
}
if
(
skb_queue_is_last
(
&
chan
->
srej_q
,
next_skb
))
break
;
}
while
((
next_skb
=
skb_queue_next
(
&
chan
->
srej_q
,
next_skb
)));
next_skb
=
NULL
;
else
next_skb
=
skb_queue_next
(
&
chan
->
srej_q
,
next_skb
);
}
__skb_queue_tail
(
&
chan
->
srej_q
,
skb
);
...
...
@@ -3788,7 +3807,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
}
}
static
void
l2cap_send_srejframe
(
struct
l2cap_chan
*
chan
,
u16
tx_seq
)
static
int
l2cap_send_srejframe
(
struct
l2cap_chan
*
chan
,
u16
tx_seq
)
{
struct
srej_list
*
new
;
u32
control
;
...
...
@@ -3799,6 +3818,9 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
l2cap_send_sframe
(
chan
,
control
);
new
=
kzalloc
(
sizeof
(
struct
srej_list
),
GFP_ATOMIC
);
if
(
!
new
)
return
-
ENOMEM
;
new
->
tx_seq
=
chan
->
expected_tx_seq
;
chan
->
expected_tx_seq
=
__next_seq
(
chan
,
chan
->
expected_tx_seq
);
...
...
@@ -3807,6 +3829,8 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
}
chan
->
expected_tx_seq
=
__next_seq
(
chan
,
chan
->
expected_tx_seq
);
return
0
;
}
static
inline
int
l2cap_data_channel_iframe
(
struct
l2cap_chan
*
chan
,
u32
rx_control
,
struct
sk_buff
*
skb
)
...
...
@@ -3877,7 +3901,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
return
0
;
}
}
l2cap_send_srejframe
(
chan
,
tx_seq
);
err
=
l2cap_send_srejframe
(
chan
,
tx_seq
);
if
(
err
<
0
)
{
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
-
err
);
return
err
;
}
}
}
else
{
expected_tx_seq_offset
=
__seq_offset
(
chan
,
...
...
@@ -3899,7 +3928,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
set_bit
(
CONN_SEND_PBIT
,
&
chan
->
conn_state
);
l2cap_send_srejframe
(
chan
,
tx_seq
);
err
=
l2cap_send_srejframe
(
chan
,
tx_seq
);
if
(
err
<
0
)
{
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
-
err
);
return
err
;
}
__clear_ack_timer
(
chan
);
}
...
...
@@ -3928,11 +3961,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
l2cap_retransmit_frames
(
chan
);
}
__set_ack_timer
(
chan
);
chan
->
num_acked
=
(
chan
->
num_acked
+
1
)
%
num_to_ack
;
if
(
chan
->
num_acked
==
num_to_ack
-
1
)
l2cap_send_ack
(
chan
);
else
__set_ack_timer
(
chan
);
return
0
;
...
...
@@ -4768,6 +4802,3 @@ void l2cap_exit(void)
module_param
(
disable_ertm
,
bool
,
0644
);
MODULE_PARM_DESC
(
disable_ertm
,
"Disable enhanced retransmission mode"
);
module_param
(
enable_hs
,
bool
,
0644
);
MODULE_PARM_DESC
(
enable_hs
,
"Enable High Speed"
);
net/bluetooth/l2cap_sock.c
View file @
5f779bbd
...
...
@@ -626,8 +626,13 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
chan
->
sec_level
=
sec
.
level
;
if
(
!
chan
->
conn
)
break
;
conn
=
chan
->
conn
;
if
(
conn
&&
chan
->
scid
==
L2CAP_CID_LE_DATA
)
{
/*change security for LE channels */
if
(
chan
->
scid
==
L2CAP_CID_LE_DATA
)
{
if
(
!
conn
->
hcon
->
out
)
{
err
=
-
EINVAL
;
break
;
...
...
@@ -635,9 +640,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
if
(
smp_conn_security
(
conn
,
sec
.
level
))
break
;
err
=
0
;
sk
->
sk_state
=
BT_CONFIG
;
/* or for ACL link, under defer_setup time */
}
else
if
(
sk
->
sk_state
==
BT_CONNECT2
&&
bt_sk
(
sk
)
->
defer_setup
)
{
err
=
l2cap_chan_check_security
(
chan
);
}
else
{
err
=
-
EINVAL
;
}
break
;
...
...
net/bluetooth/mgmt.c
View file @
5f779bbd
...
...
@@ -22,6 +22,7 @@
/* Bluetooth HCI Management interface */
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <asm/unaligned.h>
...
...
@@ -44,6 +45,79 @@ struct pending_cmd {
void
*
user_data
;
};
/* HCI to MGMT error code conversion table */
static
u8
mgmt_status_table
[]
=
{
MGMT_STATUS_SUCCESS
,
MGMT_STATUS_UNKNOWN_COMMAND
,
/* Unknown Command */
MGMT_STATUS_NOT_CONNECTED
,
/* No Connection */
MGMT_STATUS_FAILED
,
/* Hardware Failure */
MGMT_STATUS_CONNECT_FAILED
,
/* Page Timeout */
MGMT_STATUS_AUTH_FAILED
,
/* Authentication Failed */
MGMT_STATUS_NOT_PAIRED
,
/* PIN or Key Missing */
MGMT_STATUS_NO_RESOURCES
,
/* Memory Full */
MGMT_STATUS_TIMEOUT
,
/* Connection Timeout */
MGMT_STATUS_NO_RESOURCES
,
/* Max Number of Connections */
MGMT_STATUS_NO_RESOURCES
,
/* Max Number of SCO Connections */
MGMT_STATUS_ALREADY_CONNECTED
,
/* ACL Connection Exists */
MGMT_STATUS_BUSY
,
/* Command Disallowed */
MGMT_STATUS_NO_RESOURCES
,
/* Rejected Limited Resources */
MGMT_STATUS_REJECTED
,
/* Rejected Security */
MGMT_STATUS_REJECTED
,
/* Rejected Personal */
MGMT_STATUS_TIMEOUT
,
/* Host Timeout */
MGMT_STATUS_NOT_SUPPORTED
,
/* Unsupported Feature */
MGMT_STATUS_INVALID_PARAMS
,
/* Invalid Parameters */
MGMT_STATUS_DISCONNECTED
,
/* OE User Ended Connection */
MGMT_STATUS_NO_RESOURCES
,
/* OE Low Resources */
MGMT_STATUS_DISCONNECTED
,
/* OE Power Off */
MGMT_STATUS_DISCONNECTED
,
/* Connection Terminated */
MGMT_STATUS_BUSY
,
/* Repeated Attempts */
MGMT_STATUS_REJECTED
,
/* Pairing Not Allowed */
MGMT_STATUS_FAILED
,
/* Unknown LMP PDU */
MGMT_STATUS_NOT_SUPPORTED
,
/* Unsupported Remote Feature */
MGMT_STATUS_REJECTED
,
/* SCO Offset Rejected */
MGMT_STATUS_REJECTED
,
/* SCO Interval Rejected */
MGMT_STATUS_REJECTED
,
/* Air Mode Rejected */
MGMT_STATUS_INVALID_PARAMS
,
/* Invalid LMP Parameters */
MGMT_STATUS_FAILED
,
/* Unspecified Error */
MGMT_STATUS_NOT_SUPPORTED
,
/* Unsupported LMP Parameter Value */
MGMT_STATUS_FAILED
,
/* Role Change Not Allowed */
MGMT_STATUS_TIMEOUT
,
/* LMP Response Timeout */
MGMT_STATUS_FAILED
,
/* LMP Error Transaction Collision */
MGMT_STATUS_FAILED
,
/* LMP PDU Not Allowed */
MGMT_STATUS_REJECTED
,
/* Encryption Mode Not Accepted */
MGMT_STATUS_FAILED
,
/* Unit Link Key Used */
MGMT_STATUS_NOT_SUPPORTED
,
/* QoS Not Supported */
MGMT_STATUS_TIMEOUT
,
/* Instant Passed */
MGMT_STATUS_NOT_SUPPORTED
,
/* Pairing Not Supported */
MGMT_STATUS_FAILED
,
/* Transaction Collision */
MGMT_STATUS_INVALID_PARAMS
,
/* Unacceptable Parameter */
MGMT_STATUS_REJECTED
,
/* QoS Rejected */
MGMT_STATUS_NOT_SUPPORTED
,
/* Classification Not Supported */
MGMT_STATUS_REJECTED
,
/* Insufficient Security */
MGMT_STATUS_INVALID_PARAMS
,
/* Parameter Out Of Range */
MGMT_STATUS_BUSY
,
/* Role Switch Pending */
MGMT_STATUS_FAILED
,
/* Slot Violation */
MGMT_STATUS_FAILED
,
/* Role Switch Failed */
MGMT_STATUS_INVALID_PARAMS
,
/* EIR Too Large */
MGMT_STATUS_NOT_SUPPORTED
,
/* Simple Pairing Not Supported */
MGMT_STATUS_BUSY
,
/* Host Busy Pairing */
MGMT_STATUS_REJECTED
,
/* Rejected, No Suitable Channel */
MGMT_STATUS_BUSY
,
/* Controller Busy */
MGMT_STATUS_INVALID_PARAMS
,
/* Unsuitable Connection Interval */
MGMT_STATUS_TIMEOUT
,
/* Directed Advertising Timeout */
MGMT_STATUS_AUTH_FAILED
,
/* Terminated Due to MIC Failure */
MGMT_STATUS_CONNECT_FAILED
,
/* Connection Establishment Failed */
MGMT_STATUS_CONNECT_FAILED
,
/* MAC Connection Failed */
};
static
u8
mgmt_status
(
u8
hci_status
)
{
if
(
hci_status
<
ARRAY_SIZE
(
mgmt_status_table
))
return
mgmt_status_table
[
hci_status
];
return
MGMT_STATUS_FAILED
;
}
static
int
cmd_status
(
struct
sock
*
sk
,
u16
index
,
u16
cmd
,
u8
status
)
{
struct
sk_buff
*
skb
;
...
...
@@ -178,7 +252,8 @@ static int read_controller_info(struct sock *sk, u16 index)
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_INFO
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_INFO
,
MGMT_STATUS_INVALID_PARAMS
);
if
(
test_and_clear_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
cancel_delayed_work_sync
(
&
hdev
->
power_off
);
...
...
@@ -291,6 +366,15 @@ static void mgmt_pending_remove(struct pending_cmd *cmd)
mgmt_pending_free
(
cmd
);
}
static
int
send_mode_rsp
(
struct
sock
*
sk
,
u16
opcode
,
u16
index
,
u8
val
)
{
struct
mgmt_mode
rp
;
rp
.
val
=
val
;
return
cmd_complete
(
sk
,
index
,
opcode
,
&
rp
,
sizeof
(
rp
));
}
static
int
set_powered
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
mgmt_mode
*
cp
;
...
...
@@ -303,22 +387,25 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
up
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
if
((
cp
->
val
&&
up
)
||
(
!
cp
->
val
&&
!
up
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
EALREADY
);
err
=
send_mode_rsp
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
cp
->
val
);
goto
failed
;
}
if
(
mgmt_pending_find
(
MGMT_OP_SET_POWERED
,
hdev
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
EBUSY
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
MGMT_STATUS_BUSY
);
goto
failed
;
}
...
...
@@ -355,28 +442,33 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
ENETDOWN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
if
(
mgmt_pending_find
(
MGMT_OP_SET_DISCOVERABLE
,
hdev
)
||
mgmt_pending_find
(
MGMT_OP_SET_CONNECTABLE
,
hdev
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
EBUSY
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
MGMT_STATUS_BUSY
);
goto
failed
;
}
if
(
cp
->
val
==
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
)
&&
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
EALREADY
);
err
=
send_mode_rsp
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
cp
->
val
);
goto
failed
;
}
...
...
@@ -421,27 +513,32 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
ENETDOWN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
if
(
mgmt_pending_find
(
MGMT_OP_SET_DISCOVERABLE
,
hdev
)
||
mgmt_pending_find
(
MGMT_OP_SET_CONNECTABLE
,
hdev
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
EBUSY
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
MGMT_STATUS_BUSY
);
goto
failed
;
}
if
(
cp
->
val
==
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
EALREADY
);
err
=
send_mode_rsp
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
cp
->
val
);
goto
failed
;
}
...
...
@@ -496,15 +593,6 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
return
0
;
}
static
int
send_mode_rsp
(
struct
sock
*
sk
,
u16
opcode
,
u16
index
,
u8
val
)
{
struct
mgmt_mode
rp
;
rp
.
val
=
val
;
return
cmd_complete
(
sk
,
index
,
opcode
,
&
rp
,
sizeof
(
rp
));
}
static
int
set_pairable
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
...
...
@@ -517,11 +605,13 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -730,11 +820,13 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -779,11 +871,13 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -805,7 +899,8 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
}
if
(
found
==
0
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
ENOENT
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
goto
unlock
;
}
...
...
@@ -838,11 +933,13 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
"request for hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -870,11 +967,13 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -914,7 +1013,8 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
cp
=
(
void
*
)
data
;
if
(
len
<
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
key_count
=
get_unaligned_le16
(
&
cp
->
key_count
);
...
...
@@ -923,12 +1023,14 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
if
(
expected_len
!=
len
)
{
BT_ERR
(
"load_link_keys: expected %u bytes, got %u bytes"
,
len
,
expected_len
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
}
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
BT_DBG
(
"hci%u debug_keys %u key_count %u"
,
index
,
cp
->
debug_keys
,
key_count
);
...
...
@@ -951,6 +1053,8 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
key
->
pin_len
);
}
cmd_complete
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
NULL
,
0
);
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
...
...
@@ -962,41 +1066,64 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_remove_keys
*
cp
;
struct
mgmt_rp_remove_keys
rp
;
struct
hci_cp_disconnect
dc
;
struct
pending_cmd
*
cmd
;
struct
hci_conn
*
conn
;
int
err
;
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
memset
(
&
rp
,
0
,
sizeof
(
rp
));
bacpy
(
&
rp
.
bdaddr
,
&
cp
->
bdaddr
);
rp
.
status
=
MGMT_STATUS_FAILED
;
err
=
hci_remove_link_key
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
-
err
)
;
rp
.
status
=
MGMT_STATUS_NOT_PAIRED
;
goto
unlock
;
}
err
=
0
;
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
)
||
!
cp
->
disconnect
)
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
)
||
!
cp
->
disconnect
)
{
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
sizeof
(
rp
));
goto
unlock
;
}
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
cp
->
bdaddr
);
if
(
conn
)
{
struct
hci_cp_disconnect
dc
;
if
(
!
conn
)
{
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
sizeof
(
rp
));
goto
unlock
;
}
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_REMOVE_KEYS
,
hdev
,
cp
,
sizeof
(
*
cp
));
if
(
!
cmd
)
{
err
=
-
ENOMEM
;
goto
unlock
;
}
put_unaligned_le16
(
conn
->
handle
,
&
dc
.
handle
);
dc
.
reason
=
0x13
;
/* Remote User Terminated Connection */
err
=
hci_send_cmd
(
hdev
,
HCI_OP_DISCONNECT
,
sizeof
(
dc
),
&
dc
);
}
if
(
err
<
0
)
mgmt_pending_remove
(
cmd
);
unlock:
if
(
err
<
0
)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
sizeof
(
rp
));
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
...
...
@@ -1017,21 +1144,25 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
ENETDOWN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
if
(
mgmt_pending_find
(
MGMT_OP_DISCONNECT
,
hdev
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
EBUSY
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_BUSY
);
goto
failed
;
}
...
...
@@ -1040,7 +1171,8 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
LE_LINK
,
&
cp
->
bdaddr
);
if
(
!
conn
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
ENOTCONN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_NOT_CONNECTED
);
goto
failed
;
}
...
...
@@ -1064,11 +1196,18 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
err
;
}
static
u8
link_to_mgmt
(
u8
link_type
)
static
u8
link_to_mgmt
(
u8
link_type
,
u8
addr_type
)
{
switch
(
link_type
)
{
case
LE_LINK
:
return
MGMT_ADDR_LE
;
switch
(
addr_type
)
{
case
ADDR_LE_DEV_PUBLIC
:
return
MGMT_ADDR_LE_PUBLIC
;
case
ADDR_LE_DEV_RANDOM
:
return
MGMT_ADDR_LE_RANDOM
;
default:
return
MGMT_ADDR_INVALID
;
}
case
ACL_LINK
:
return
MGMT_ADDR_BREDR
;
default:
...
...
@@ -1090,7 +1229,8 @@ static int get_connections(struct sock *sk, u16 index)
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_GET_CONNECTIONS
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_GET_CONNECTIONS
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -1111,7 +1251,7 @@ static int get_connections(struct sock *sk, u16 index)
i
=
0
;
list_for_each_entry
(
c
,
&
hdev
->
conn_hash
.
list
,
list
)
{
bacpy
(
&
rp
->
addr
[
i
].
bdaddr
,
&
c
->
dst
);
rp
->
addr
[
i
].
type
=
link_to_mgmt
(
c
->
type
);
rp
->
addr
[
i
].
type
=
link_to_mgmt
(
c
->
type
,
c
->
dst_type
);
if
(
rp
->
addr
[
i
].
type
==
MGMT_ADDR_INVALID
)
continue
;
i
++
;
...
...
@@ -1164,22 +1304,26 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
ENETDOWN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
cp
->
bdaddr
);
if
(
!
conn
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
ENOTCONN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
MGMT_STATUS_NOT_CONNECTED
);
goto
failed
;
}
...
...
@@ -1191,7 +1335,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
err
=
send_pin_code_neg_reply
(
sk
,
index
,
hdev
,
&
ncp
);
if
(
err
>=
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
goto
failed
;
}
...
...
@@ -1230,18 +1374,18 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
ENETDOWN
);
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
...
...
@@ -1265,11 +1409,13 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -1307,7 +1453,8 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
struct
mgmt_rp_pair_device
rp
;
struct
hci_conn
*
conn
=
cmd
->
user_data
;
bacpy
(
&
rp
.
bdaddr
,
&
conn
->
dst
);
bacpy
(
&
rp
.
addr
.
bdaddr
,
&
conn
->
dst
);
rp
.
addr
.
type
=
link_to_mgmt
(
conn
->
type
,
conn
->
dst_type
);
rp
.
status
=
status
;
cmd_complete
(
cmd
->
sk
,
cmd
->
index
,
MGMT_OP_PAIR_DEVICE
,
&
rp
,
sizeof
(
rp
));
...
...
@@ -1325,27 +1472,22 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
static
void
pairing_complete_cb
(
struct
hci_conn
*
conn
,
u8
status
)
{
struct
pending_cmd
*
cmd
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"status %u"
,
status
);
hci_dev_lock_bh
(
hdev
);
cmd
=
find_pairing
(
conn
);
if
(
!
cmd
)
BT_DBG
(
"Unable to find a pending command"
);
else
pairing_complete
(
cmd
,
status
);
hci_dev_unlock_bh
(
hdev
);
}
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
mgmt_rp_pair_device
rp
;
struct
pending_cmd
*
cmd
;
struct
adv_entry
*
entry
;
u8
sec_level
,
auth_type
;
struct
hci_conn
*
conn
;
int
err
;
...
...
@@ -1355,11 +1497,13 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -1369,22 +1513,29 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
auth_type
=
HCI_AT_DEDICATED_BONDING_MITM
;
entry
=
hci_find_adv_entry
(
hdev
,
&
cp
->
bdaddr
);
if
(
entry
)
conn
=
hci_connect
(
hdev
,
LE_LINK
,
&
cp
->
bdaddr
,
sec_level
,
if
(
cp
->
addr
.
type
==
MGMT_ADDR_BREDR
)
conn
=
hci_connect
(
hdev
,
ACL_LINK
,
&
cp
->
addr
.
bdaddr
,
sec_level
,
auth_type
);
else
conn
=
hci_connect
(
hdev
,
ACL_LINK
,
&
cp
->
bdaddr
,
sec_level
,
conn
=
hci_connect
(
hdev
,
LE_LINK
,
&
cp
->
addr
.
bdaddr
,
sec_level
,
auth_type
);
memset
(
&
rp
,
0
,
sizeof
(
rp
));
bacpy
(
&
rp
.
addr
.
bdaddr
,
&
cp
->
addr
.
bdaddr
);
rp
.
addr
.
type
=
cp
->
addr
.
type
;
if
(
IS_ERR
(
conn
))
{
err
=
PTR_ERR
(
conn
);
rp
.
status
=
-
PTR_ERR
(
conn
);
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
&
rp
,
sizeof
(
rp
));
goto
unlock
;
}
if
(
conn
->
connect_cfm_cb
)
{
hci_conn_put
(
conn
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
EBUSY
);
rp
.
status
=
EBUSY
;
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
&
rp
,
sizeof
(
rp
));
goto
unlock
;
}
...
...
@@ -1396,7 +1547,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
}
/* For LE, just connecting isn't a proof that the pairing finished */
if
(
!
entry
)
if
(
cp
->
addr
.
type
==
MGMT_ADDR_BREDR
)
conn
->
connect_cfm_cb
=
pairing_complete_cb
;
conn
->
security_cfm_cb
=
pairing_complete_cb
;
...
...
@@ -1417,56 +1568,138 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
err
;
}
static
int
user_
confirm_reply
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
,
int
success
)
static
int
user_
pairing_resp
(
struct
sock
*
sk
,
u16
index
,
bdaddr_t
*
bdaddr
,
u16
mgmt_op
,
u16
hci_op
,
__le32
passkey
)
{
struct
mgmt_cp_user_confirm_reply
*
cp
=
(
void
*
)
data
;
u16
mgmt_op
,
hci_op
;
struct
pending_cmd
*
cmd
;
struct
hci_dev
*
hdev
;
struct
hci_conn
*
conn
;
int
err
;
BT_DBG
(
""
);
if
(
success
)
{
mgmt_op
=
MGMT_OP_USER_CONFIRM_REPLY
;
hci_op
=
HCI_OP_USER_CONFIRM_REPLY
;
}
else
{
mgmt_op
=
MGMT_OP_USER_CONFIRM_NEG_REPLY
;
hci_op
=
HCI_OP_USER_CONFIRM_NEG_REPLY
;
}
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
mgmt_op
,
EINVAL
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
mgmt_op
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
ENETDOWN
);
goto
failed
;
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_NOT_POWERED
);
goto
done
;
}
/*
* Check for an existing ACL link, if present pair via
* HCI commands.
*
* If no ACL link is present, check for an LE link and if
* present, pair via the SMP engine.
*
* If neither ACL nor LE links are present, fail with error.
*/
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
bdaddr
);
if
(
!
conn
)
{
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
LE_LINK
,
bdaddr
);
if
(
!
conn
)
{
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_NOT_CONNECTED
);
goto
done
;
}
cmd
=
mgmt_pending_add
(
sk
,
mgmt_op
,
hdev
,
data
,
len
);
/* Continue with pairing via SMP */
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_SUCCESS
);
goto
done
;
}
cmd
=
mgmt_pending_add
(
sk
,
mgmt_op
,
hdev
,
bdaddr
,
sizeof
(
*
bdaddr
));
if
(
!
cmd
)
{
err
=
-
ENOMEM
;
goto
failed
;
goto
done
;
}
err
=
hci_send_cmd
(
hdev
,
hci_op
,
sizeof
(
cp
->
bdaddr
),
&
cp
->
bdaddr
);
/* Continue with pairing via HCI */
if
(
hci_op
==
HCI_OP_USER_PASSKEY_REPLY
)
{
struct
hci_cp_user_passkey_reply
cp
;
bacpy
(
&
cp
.
bdaddr
,
bdaddr
);
cp
.
passkey
=
passkey
;
err
=
hci_send_cmd
(
hdev
,
hci_op
,
sizeof
(
cp
),
&
cp
);
}
else
err
=
hci_send_cmd
(
hdev
,
hci_op
,
sizeof
(
*
bdaddr
),
bdaddr
);
if
(
err
<
0
)
mgmt_pending_remove
(
cmd
);
failed
:
done
:
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
}
static
int
user_confirm_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
u16
len
)
{
struct
mgmt_cp_user_confirm_reply
*
cp
=
(
void
*
)
data
;
BT_DBG
(
""
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_USER_CONFIRM_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
return
user_pairing_resp
(
sk
,
index
,
&
cp
->
bdaddr
,
MGMT_OP_USER_CONFIRM_REPLY
,
HCI_OP_USER_CONFIRM_REPLY
,
0
);
}
static
int
user_confirm_neg_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
u16
len
)
{
struct
mgmt_cp_user_confirm_reply
*
cp
=
(
void
*
)
data
;
BT_DBG
(
""
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_USER_CONFIRM_NEG_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
return
user_pairing_resp
(
sk
,
index
,
&
cp
->
bdaddr
,
MGMT_OP_USER_CONFIRM_NEG_REPLY
,
HCI_OP_USER_CONFIRM_NEG_REPLY
,
0
);
}
static
int
user_passkey_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
u16
len
)
{
struct
mgmt_cp_user_passkey_reply
*
cp
=
(
void
*
)
data
;
BT_DBG
(
""
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_USER_PASSKEY_REPLY
,
EINVAL
);
return
user_pairing_resp
(
sk
,
index
,
&
cp
->
bdaddr
,
MGMT_OP_USER_PASSKEY_REPLY
,
HCI_OP_USER_PASSKEY_REPLY
,
cp
->
passkey
);
}
static
int
user_passkey_neg_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
u16
len
)
{
struct
mgmt_cp_user_passkey_neg_reply
*
cp
=
(
void
*
)
data
;
BT_DBG
(
""
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_USER_PASSKEY_NEG_REPLY
,
EINVAL
);
return
user_pairing_resp
(
sk
,
index
,
&
cp
->
bdaddr
,
MGMT_OP_USER_PASSKEY_NEG_REPLY
,
HCI_OP_USER_PASSKEY_NEG_REPLY
,
0
);
}
static
int
set_local_name
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
...
...
@@ -1479,11 +1712,13 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
""
);
if
(
len
!=
sizeof
(
*
mgmt_cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
EINVAL
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -1517,24 +1752,25 @@ static int read_local_oob_data(struct sock *sk, u16 index)
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
ENETDOWN
);
MGMT_STATUS_NOT_POWERED
);
goto
unlock
;
}
if
(
!
(
hdev
->
features
[
6
]
&
LMP_SIMPLE_PAIR
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
EOPNOTSUPP
);
MGMT_STATUS_NOT_SUPPORTED
);
goto
unlock
;
}
if
(
mgmt_pending_find
(
MGMT_OP_READ_LOCAL_OOB_DATA
,
hdev
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
EBUSY
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
MGMT_STATUS_BUSY
);
goto
unlock
;
}
...
...
@@ -1566,19 +1802,20 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_add_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
,
cp
->
hash
,
cp
->
randomizer
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
-
err
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
MGMT_STATUS_FAILED
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
NULL
,
0
);
...
...
@@ -1600,19 +1837,19 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_remove_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
-
err
);
MGMT_STATUS_INVALID_PARAMS
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
NULL
,
0
);
...
...
@@ -1623,22 +1860,30 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return
err
;
}
static
int
start_discovery
(
struct
sock
*
sk
,
u16
index
)
static
int
start_discovery
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
mgmt_cp_start_discovery
*
cp
=
(
void
*
)
data
;
struct
pending_cmd
*
cmd
;
struct
hci_dev
*
hdev
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
ENETDOWN
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
MGMT_STATUS_NOT_POWERED
);
goto
failed
;
}
...
...
@@ -1669,7 +1914,8 @@ static int stop_discovery(struct sock *sk, u16 index)
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_STOP_DISCOVERY
,
ENODEV
);
return
cmd_status
(
sk
,
index
,
MGMT_OP_STOP_DISCOVERY
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
...
...
@@ -1701,18 +1947,19 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_blacklist_add
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
-
err
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
MGMT_STATUS_FAILED
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
NULL
,
0
);
...
...
@@ -1734,19 +1981,20 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
err
=
hci_blacklist_del
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
-
err
);
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
NULL
,
0
);
...
...
@@ -1770,12 +2018,12 @@ static int set_fast_connectable(struct sock *sk, u16 index,
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
EINVAL
);
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
ENODEV
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
(
hdev
);
...
...
@@ -1793,14 +2041,14 @@ static int set_fast_connectable(struct sock *sk, u16 index,
sizeof
(
acp
),
&
acp
);
if
(
err
<
0
)
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_FAST_CONNECTABLE
,
-
err
);
MGMT_STATUS_FAILED
);
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
);
MGMT_STATUS_FAILED
);
goto
done
;
}
...
...
@@ -1903,10 +2151,18 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
err
=
pair_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_USER_CONFIRM_REPLY
:
err
=
user_confirm_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
,
1
);
err
=
user_confirm_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_USER_CONFIRM_NEG_REPLY
:
err
=
user_confirm_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
,
0
);
err
=
user_confirm_neg_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_USER_PASSKEY_REPLY
:
err
=
user_passkey_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_USER_PASSKEY_NEG_REPLY
:
err
=
user_passkey_neg_reply
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_SET_LOCAL_NAME
:
err
=
set_local_name
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
...
...
@@ -1922,7 +2178,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
len
);
break
;
case
MGMT_OP_START_DISCOVERY
:
err
=
start_discovery
(
sk
,
index
);
err
=
start_discovery
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_STOP_DISCOVERY
:
err
=
stop_discovery
(
sk
,
index
);
...
...
@@ -1939,7 +2195,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
break
;
default:
BT_DBG
(
"Unknown op %u"
,
opcode
);
err
=
cmd_status
(
sk
,
index
,
opcode
,
0x01
);
err
=
cmd_status
(
sk
,
index
,
opcode
,
MGMT_STATUS_UNKNOWN_COMMAND
);
break
;
}
...
...
@@ -2062,13 +2319,15 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
int
mgmt_write_scan_failed
(
struct
hci_dev
*
hdev
,
u8
scan
,
u8
status
)
{
u8
mgmt_err
=
mgmt_status
(
status
);
if
(
scan
&
SCAN_PAGE
)
mgmt_pending_foreach
(
MGMT_OP_SET_CONNECTABLE
,
hdev
,
cmd_status_rsp
,
&
status
);
cmd_status_rsp
,
&
mgmt_err
);
if
(
scan
&
SCAN_INQUIRY
)
mgmt_pending_foreach
(
MGMT_OP_SET_DISCOVERABLE
,
hdev
,
cmd_status_rsp
,
&
status
);
cmd_status_rsp
,
&
mgmt_err
);
return
0
;
}
...
...
@@ -2089,12 +2348,13 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
return
mgmt_event
(
MGMT_EV_NEW_LINK_KEY
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
int
mgmt_connected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
)
int
mgmt_connected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
,
u8
addr_type
)
{
struct
mgmt_addr_info
ev
;
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
ev
.
type
=
link_to_mgmt
(
link_type
);
ev
.
type
=
link_to_mgmt
(
link_type
,
addr_type
);
return
mgmt_event
(
MGMT_EV_CONNECTED
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
...
...
@@ -2106,6 +2366,7 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
struct
mgmt_rp_disconnect
rp
;
bacpy
(
&
rp
.
bdaddr
,
&
cp
->
bdaddr
);
rp
.
status
=
0
;
cmd_complete
(
cmd
->
sk
,
cmd
->
index
,
MGMT_OP_DISCONNECT
,
&
rp
,
sizeof
(
rp
));
...
...
@@ -2115,7 +2376,25 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_remove
(
cmd
);
}
int
mgmt_disconnected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
)
static
void
remove_keys_rsp
(
struct
pending_cmd
*
cmd
,
void
*
data
)
{
u8
*
status
=
data
;
struct
mgmt_cp_remove_keys
*
cp
=
cmd
->
param
;
struct
mgmt_rp_remove_keys
rp
;
memset
(
&
rp
,
0
,
sizeof
(
rp
));
bacpy
(
&
rp
.
bdaddr
,
&
cp
->
bdaddr
);
if
(
status
!=
NULL
)
rp
.
status
=
*
status
;
cmd_complete
(
cmd
->
sk
,
cmd
->
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
sizeof
(
rp
));
mgmt_pending_remove
(
cmd
);
}
int
mgmt_disconnected
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_type
,
u8
addr_type
)
{
struct
mgmt_addr_info
ev
;
struct
sock
*
sk
=
NULL
;
...
...
@@ -2124,40 +2403,53 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
mgmt_pending_foreach
(
MGMT_OP_DISCONNECT
,
hdev
,
disconnect_rsp
,
&
sk
);
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
ev
.
type
=
link_to_mgmt
(
type
);
ev
.
type
=
link_to_mgmt
(
link_type
,
addr_
type
);
err
=
mgmt_event
(
MGMT_EV_DISCONNECTED
,
hdev
,
&
ev
,
sizeof
(
ev
),
sk
);
if
(
sk
)
sock_put
(
sk
);
mgmt_pending_foreach
(
MGMT_OP_REMOVE_KEYS
,
hdev
,
remove_keys_rsp
,
NULL
);
return
err
;
}
int
mgmt_disconnect_failed
(
struct
hci_dev
*
hdev
)
int
mgmt_disconnect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
struct
pending_cmd
*
cmd
;
u8
mgmt_err
=
mgmt_status
(
status
);
int
err
;
cmd
=
mgmt_pending_find
(
MGMT_OP_DISCONNECT
,
hdev
);
if
(
!
cmd
)
return
-
ENOENT
;
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_DISCONNECT
,
EIO
);
if
(
bdaddr
)
{
struct
mgmt_rp_disconnect
rp
;
bacpy
(
&
rp
.
bdaddr
,
bdaddr
);
rp
.
status
=
status
;
err
=
cmd_complete
(
cmd
->
sk
,
cmd
->
index
,
MGMT_OP_DISCONNECT
,
&
rp
,
sizeof
(
rp
));
}
else
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_DISCONNECT
,
mgmt_err
);
mgmt_pending_remove
(
cmd
);
return
err
;
}
int
mgmt_connect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
,
u8
status
)
int
mgmt_connect_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_
type
,
u8
addr_type
,
u8
status
)
{
struct
mgmt_ev_connect_failed
ev
;
bacpy
(
&
ev
.
addr
.
bdaddr
,
bdaddr
);
ev
.
addr
.
type
=
link_to_mgmt
(
type
);
ev
.
status
=
status
;
ev
.
addr
.
type
=
link_to_mgmt
(
link_type
,
addr_
type
);
ev
.
status
=
mgmt_status
(
status
)
;
return
mgmt_event
(
MGMT_EV_CONNECT_FAILED
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
...
...
@@ -2185,7 +2477,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return
-
ENOENT
;
bacpy
(
&
rp
.
bdaddr
,
bdaddr
);
rp
.
status
=
status
;
rp
.
status
=
mgmt_status
(
status
)
;
err
=
cmd_complete
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_PIN_CODE_REPLY
,
&
rp
,
sizeof
(
rp
));
...
...
@@ -2207,7 +2499,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return
-
ENOENT
;
bacpy
(
&
rp
.
bdaddr
,
bdaddr
);
rp
.
status
=
status
;
rp
.
status
=
mgmt_status
(
status
)
;
err
=
cmd_complete
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
&
rp
,
sizeof
(
rp
));
...
...
@@ -2232,7 +2524,19 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
NULL
);
}
static
int
confirm_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
int
mgmt_user_passkey_request
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
mgmt_ev_user_passkey_request
ev
;
BT_DBG
(
"%s"
,
hdev
->
name
);
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
return
mgmt_event
(
MGMT_EV_USER_PASSKEY_REQUEST
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
static
int
user_pairing_resp_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
,
u8
opcode
)
{
struct
pending_cmd
*
cmd
;
...
...
@@ -2244,7 +2548,7 @@ static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return
-
ENOENT
;
bacpy
(
&
rp
.
bdaddr
,
bdaddr
);
rp
.
status
=
status
;
rp
.
status
=
mgmt_status
(
status
)
;
err
=
cmd_complete
(
cmd
->
sk
,
hdev
->
id
,
opcode
,
&
rp
,
sizeof
(
rp
));
mgmt_pending_remove
(
cmd
);
...
...
@@ -2255,23 +2559,37 @@ static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
int
mgmt_user_confirm_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
return
confirm_reply
_complete
(
hdev
,
bdaddr
,
status
,
return
user_pairing_resp
_complete
(
hdev
,
bdaddr
,
status
,
MGMT_OP_USER_CONFIRM_REPLY
);
}
int
mgmt_user_confirm_neg_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
return
confirm_reply
_complete
(
hdev
,
bdaddr
,
status
,
return
user_pairing_resp
_complete
(
hdev
,
bdaddr
,
status
,
MGMT_OP_USER_CONFIRM_NEG_REPLY
);
}
int
mgmt_user_passkey_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
return
user_pairing_resp_complete
(
hdev
,
bdaddr
,
status
,
MGMT_OP_USER_PASSKEY_REPLY
);
}
int
mgmt_user_passkey_neg_reply_complete
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
return
user_pairing_resp_complete
(
hdev
,
bdaddr
,
status
,
MGMT_OP_USER_PASSKEY_NEG_REPLY
);
}
int
mgmt_auth_failed
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
status
)
{
struct
mgmt_ev_auth_failed
ev
;
bacpy
(
&
ev
.
bdaddr
,
bdaddr
);
ev
.
status
=
status
;
ev
.
status
=
mgmt_status
(
status
)
;
return
mgmt_event
(
MGMT_EV_AUTH_FAILED
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
...
...
@@ -2291,7 +2609,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
if
(
status
)
{
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_SET_LOCAL_NAME
,
EIO
);
mgmt_status
(
status
)
);
goto
failed
;
}
...
...
@@ -2326,7 +2644,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
if
(
status
)
{
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
EIO
);
MGMT_OP_READ_LOCAL_OOB_DATA
,
mgmt_status
(
status
));
}
else
{
struct
mgmt_rp_read_local_oob_data
rp
;
...
...
@@ -2343,15 +2662,15 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
return
err
;
}
int
mgmt_device_found
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
,
u8
*
dev_class
,
s8
rssi
,
u8
*
eir
)
int
mgmt_device_found
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
link_
type
,
u8
addr_type
,
u8
*
dev_class
,
s8
rssi
,
u8
*
eir
)
{
struct
mgmt_ev_device_found
ev
;
memset
(
&
ev
,
0
,
sizeof
(
ev
));
bacpy
(
&
ev
.
addr
.
bdaddr
,
bdaddr
);
ev
.
addr
.
type
=
link_to_mgmt
(
type
);
ev
.
addr
.
type
=
link_to_mgmt
(
link_type
,
addr_
type
);
ev
.
rssi
=
rssi
;
if
(
eir
)
...
...
@@ -2375,7 +2694,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
return
mgmt_event
(
MGMT_EV_REMOTE_NAME
,
hdev
,
&
ev
,
sizeof
(
ev
),
NULL
);
}
int
mgmt_
inqui
ry_failed
(
struct
hci_dev
*
hdev
,
u8
status
)
int
mgmt_
start_discove
ry_failed
(
struct
hci_dev
*
hdev
,
u8
status
)
{
struct
pending_cmd
*
cmd
;
int
err
;
...
...
@@ -2384,6 +2703,21 @@ int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
if
(
!
cmd
)
return
-
ENOENT
;
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
cmd
->
opcode
,
mgmt_status
(
status
));
mgmt_pending_remove
(
cmd
);
return
err
;
}
int
mgmt_stop_discovery_failed
(
struct
hci_dev
*
hdev
,
u8
status
)
{
struct
pending_cmd
*
cmd
;
int
err
;
cmd
=
mgmt_pending_find
(
MGMT_OP_STOP_DISCOVERY
,
hdev
);
if
(
!
cmd
)
return
-
ENOENT
;
err
=
cmd_status
(
cmd
->
sk
,
hdev
->
id
,
cmd
->
opcode
,
status
);
mgmt_pending_remove
(
cmd
);
...
...
net/bluetooth/smp.c
View file @
5f779bbd
...
...
@@ -232,6 +232,18 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
return
0
;
}
static
void
smp_failure
(
struct
l2cap_conn
*
conn
,
u8
reason
,
u8
send
)
{
if
(
send
)
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
hcon
->
pend
);
mgmt_auth_failed
(
conn
->
hcon
->
hdev
,
conn
->
dst
,
reason
);
del_timer
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
}
static
void
confirm_work
(
struct
work_struct
*
work
)
{
struct
smp_chan
*
smp
=
container_of
(
work
,
struct
smp_chan
,
confirm
);
...
...
@@ -270,8 +282,7 @@ static void confirm_work(struct work_struct *work)
return
;
error:
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
smp_chan_destroy
(
conn
);
smp_failure
(
conn
,
reason
,
1
);
}
static
void
random_work
(
struct
work_struct
*
work
)
...
...
@@ -354,8 +365,7 @@ static void random_work(struct work_struct *work)
return
;
error:
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
smp_chan_destroy
(
conn
);
smp_failure
(
conn
,
reason
,
1
);
}
static
struct
smp_chan
*
smp_chan_create
(
struct
l2cap_conn
*
conn
)
...
...
@@ -379,7 +389,15 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
void
smp_chan_destroy
(
struct
l2cap_conn
*
conn
)
{
kfree
(
conn
->
smp_chan
);
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
);
if
(
smp
->
tfm
)
crypto_free_blkcipher
(
smp
->
tfm
);
kfree
(
smp
);
conn
->
smp_chan
=
NULL
;
hci_conn_put
(
conn
->
hcon
);
}
...
...
@@ -647,6 +665,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
break
;
case
SMP_CMD_PAIRING_FAIL
:
smp_failure
(
conn
,
skb
->
data
[
0
],
0
);
reason
=
0
;
err
=
-
EPERM
;
break
;
...
...
@@ -692,8 +711,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
done:
if
(
reason
)
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
smp_failure
(
conn
,
reason
,
1
);
kfree_skb
(
skb
);
return
err
;
...
...
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