forked from Minki/linux
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
9fbdc75116
@ -1619,6 +1619,7 @@ static struct usb_driver btusb_driver = {
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = btusb_suspend,
|
||||
.resume = btusb_resume,
|
||||
.reset_resume = btusb_resume,
|
||||
#endif
|
||||
.id_table = btusb_table,
|
||||
.supports_autosuspend = 1,
|
||||
|
@ -107,7 +107,6 @@ enum {
|
||||
HCI_MGMT,
|
||||
HCI_PAIRABLE,
|
||||
HCI_SERVICE_CACHE,
|
||||
HCI_LINK_KEYS,
|
||||
HCI_DEBUG_KEYS,
|
||||
HCI_UNREGISTER,
|
||||
|
||||
|
@ -117,13 +117,6 @@ struct oob_data {
|
||||
u8 randomizer[16];
|
||||
};
|
||||
|
||||
struct le_scan_params {
|
||||
u8 type;
|
||||
u16 interval;
|
||||
u16 window;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
#define HCI_MAX_SHORT_NAME_LENGTH 10
|
||||
|
||||
struct amp_assoc {
|
||||
@ -283,9 +276,6 @@ struct hci_dev {
|
||||
|
||||
struct delayed_work le_scan_disable;
|
||||
|
||||
struct work_struct le_scan;
|
||||
struct le_scan_params le_scan_params;
|
||||
|
||||
__s8 adv_tx_power;
|
||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
||||
__u8 adv_data_len;
|
||||
@ -432,6 +422,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
|
||||
struct inquiry_entry *ie);
|
||||
bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
||||
bool name_known, bool *ssp);
|
||||
void hci_inquiry_cache_flush(struct hci_dev *hdev);
|
||||
|
||||
/* ----- HCI Connections ----- */
|
||||
enum {
|
||||
@ -1114,6 +1105,16 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
||||
BIT(BDADDR_LE_PUBLIC) | \
|
||||
BIT(BDADDR_LE_RANDOM))
|
||||
|
||||
/* These LE scan and inquiry parameters were chosen according to LE General
|
||||
* Discovery Procedure specification.
|
||||
*/
|
||||
#define DISCOV_LE_SCAN_WIN 0x12
|
||||
#define DISCOV_LE_SCAN_INT 0x12
|
||||
#define DISCOV_LE_TIMEOUT msecs_to_jiffies(10240)
|
||||
#define DISCOV_INTERLEAVED_TIMEOUT msecs_to_jiffies(5120)
|
||||
#define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
|
||||
#define DISCOV_BREDR_INQUIRY_LEN 0x08
|
||||
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
int mgmt_index_added(struct hci_dev *hdev);
|
||||
int mgmt_index_removed(struct hci_dev *hdev);
|
||||
@ -1169,10 +1170,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 ssp, u8 *eir, u16 eir_len);
|
||||
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
|
||||
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_interleaved_discovery(struct hci_dev *hdev);
|
||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
bool mgmt_valid_hdev(struct hci_dev *hdev);
|
||||
@ -1212,11 +1210,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
u16 latency, u16 to_multiplier);
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
__u8 ltk[16]);
|
||||
int hci_do_inquiry(struct hci_dev *hdev, u8 length);
|
||||
int hci_cancel_inquiry(struct hci_dev *hdev);
|
||||
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
|
||||
int timeout);
|
||||
int hci_cancel_le_scan(struct hci_dev *hdev);
|
||||
|
||||
u8 bdaddr_to_le(u8 bdaddr_type);
|
||||
|
||||
|
@ -242,7 +242,7 @@ struct l2cap_conn_rsp {
|
||||
#define L2CAP_CID_SIGNALING 0x0001
|
||||
#define L2CAP_CID_CONN_LESS 0x0002
|
||||
#define L2CAP_CID_A2MP 0x0003
|
||||
#define L2CAP_CID_LE_DATA 0x0004
|
||||
#define L2CAP_CID_ATT 0x0004
|
||||
#define L2CAP_CID_LE_SIGNALING 0x0005
|
||||
#define L2CAP_CID_SMP 0x0006
|
||||
#define L2CAP_CID_DYN_START 0x0040
|
||||
|
@ -597,7 +597,15 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
|
||||
struct hci_dev *hdev = req->hdev;
|
||||
u8 p;
|
||||
|
||||
/* Only send HCI_Delete_Stored_Link_Key if it is supported */
|
||||
/* Some Broadcom based Bluetooth controllers do not support the
|
||||
* Delete Stored Link Key command. They are clearly indicating its
|
||||
* absence in the bit mask of supported commands.
|
||||
*
|
||||
* Check the supported commands and only if the the command is marked
|
||||
* as supported send it. If not supported assume that the controller
|
||||
* does not have actual support for stored link keys which makes this
|
||||
* command redundant anyway.
|
||||
*/
|
||||
if (hdev->commands[6] & 0x80) {
|
||||
struct hci_cp_delete_stored_link_key cp;
|
||||
|
||||
@ -751,7 +759,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
|
||||
hdev->discovery.state = state;
|
||||
}
|
||||
|
||||
static void inquiry_cache_flush(struct hci_dev *hdev)
|
||||
void hci_inquiry_cache_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct discovery_state *cache = &hdev->discovery;
|
||||
struct inquiry_entry *p, *n;
|
||||
@ -964,7 +972,7 @@ int hci_inquiry(void __user *arg)
|
||||
hci_dev_lock(hdev);
|
||||
if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
|
||||
inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
|
||||
inquiry_cache_flush(hdev);
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
do_inquiry = 1;
|
||||
}
|
||||
hci_dev_unlock(hdev);
|
||||
@ -1201,8 +1209,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s %p", hdev->name, hdev);
|
||||
|
||||
cancel_work_sync(&hdev->le_scan);
|
||||
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
|
||||
hci_req_cancel(hdev, ENODEV);
|
||||
@ -1230,7 +1236,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||
cancel_delayed_work_sync(&hdev->le_scan_disable);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
inquiry_cache_flush(hdev);
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
hci_conn_hash_flush(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -1331,7 +1337,7 @@ int hci_dev_reset(__u16 dev)
|
||||
skb_queue_purge(&hdev->cmd_q);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
inquiry_cache_flush(hdev);
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
hci_conn_hash_flush(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -1991,80 +1997,59 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
|
||||
return mgmt_device_unblocked(hdev, bdaddr, type);
|
||||
}
|
||||
|
||||
static void le_scan_param_req(struct hci_request *req, unsigned long opt)
|
||||
static void inquiry_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct le_scan_params *param = (struct le_scan_params *) opt;
|
||||
struct hci_cp_le_set_scan_param cp;
|
||||
if (status) {
|
||||
BT_ERR("Failed to start inquiry: status %d", status);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.type = param->type;
|
||||
cp.interval = cpu_to_le16(param->interval);
|
||||
cp.window = cpu_to_le16(param->window);
|
||||
|
||||
hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
|
||||
static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_cp_le_set_scan_enable cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.enable = LE_SCAN_ENABLE;
|
||||
cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
|
||||
|
||||
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
|
||||
u16 window, int timeout)
|
||||
{
|
||||
long timeo = msecs_to_jiffies(3000);
|
||||
struct le_scan_params param;
|
||||
/* General inquiry access code (GIAC) */
|
||||
u8 lap[3] = { 0x33, 0x8b, 0x9e };
|
||||
struct hci_request req;
|
||||
struct hci_cp_inquiry cp;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
|
||||
return -EINPROGRESS;
|
||||
|
||||
param.type = type;
|
||||
param.interval = interval;
|
||||
param.window = window;
|
||||
|
||||
hci_req_lock(hdev);
|
||||
|
||||
err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) ¶m,
|
||||
timeo);
|
||||
if (!err)
|
||||
err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
|
||||
|
||||
hci_req_unlock(hdev);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||
timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_cancel_le_scan(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
|
||||
return -EALREADY;
|
||||
|
||||
if (cancel_delayed_work(&hdev->le_scan_disable)) {
|
||||
struct hci_cp_le_set_scan_enable cp;
|
||||
|
||||
/* Send HCI command to disable LE Scan */
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
||||
if (status) {
|
||||
BT_ERR("Failed to disable LE scanning: status %d", status);
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
switch (hdev->discovery.type) {
|
||||
case DISCOV_TYPE_LE:
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
hci_dev_unlock(hdev);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
memcpy(&cp.lap, lap, sizeof(cp.lap));
|
||||
cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
|
||||
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
|
||||
err = hci_req_run(&req, inquiry_complete);
|
||||
if (err) {
|
||||
BT_ERR("Inquiry request failed: err %d", err);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void le_scan_disable_work(struct work_struct *work)
|
||||
@ -2072,46 +2057,20 @@ static void le_scan_disable_work(struct work_struct *work)
|
||||
struct hci_dev *hdev = container_of(work, struct hci_dev,
|
||||
le_scan_disable.work);
|
||||
struct hci_cp_le_set_scan_enable cp;
|
||||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.enable = LE_SCAN_DISABLE;
|
||||
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void le_scan_work(struct work_struct *work)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
|
||||
struct le_scan_params *param = &hdev->le_scan_params;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_do_le_scan(hdev, param->type, param->interval, param->window,
|
||||
param->timeout);
|
||||
}
|
||||
|
||||
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
|
||||
int timeout)
|
||||
{
|
||||
struct le_scan_params *param = &hdev->le_scan_params;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (work_busy(&hdev->le_scan))
|
||||
return -EINPROGRESS;
|
||||
|
||||
param->type = type;
|
||||
param->interval = interval;
|
||||
param->window = window;
|
||||
param->timeout = timeout;
|
||||
|
||||
queue_work(system_long_wq, &hdev->le_scan);
|
||||
|
||||
return 0;
|
||||
err = hci_req_run(&req, le_scan_disable_work_complete);
|
||||
if (err)
|
||||
BT_ERR("Disable LE scanning request failed: err %d", err);
|
||||
}
|
||||
|
||||
/* Alloc HCI device */
|
||||
@ -2148,7 +2107,6 @@ struct hci_dev *hci_alloc_dev(void)
|
||||
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
|
||||
INIT_WORK(&hdev->tx_work, hci_tx_work);
|
||||
INIT_WORK(&hdev->power_on, hci_power_on);
|
||||
INIT_WORK(&hdev->le_scan, le_scan_work);
|
||||
|
||||
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
|
||||
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
|
||||
@ -3551,36 +3509,6 @@ static void hci_cmd_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
int hci_do_inquiry(struct hci_dev *hdev, u8 length)
|
||||
{
|
||||
/* General inquiry access code (GIAC) */
|
||||
u8 lap[3] = { 0x33, 0x8b, 0x9e };
|
||||
struct hci_cp_inquiry cp;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (test_bit(HCI_INQUIRY, &hdev->flags))
|
||||
return -EINPROGRESS;
|
||||
|
||||
inquiry_cache_flush(hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
memcpy(&cp.lap, lap, sizeof(cp.lap));
|
||||
cp.length = length;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
int hci_cancel_inquiry(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_bit(HCI_INQUIRY, &hdev->flags))
|
||||
return -EALREADY;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
||||
}
|
||||
|
||||
u8 bdaddr_to_le(u8 bdaddr_type)
|
||||
{
|
||||
switch (bdaddr_type) {
|
||||
|
@ -40,21 +40,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_stop_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
if (status)
|
||||
return;
|
||||
}
|
||||
|
||||
clear_bit(HCI_INQUIRY, &hdev->flags);
|
||||
smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
|
||||
wake_up_bit(&hdev->flags, HCI_INQUIRY);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_conn_check_pending(hdev);
|
||||
}
|
||||
|
||||
@ -937,20 +929,6 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
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%2.2x", hdev->name, status);
|
||||
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -963,41 +941,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
switch (cp->enable) {
|
||||
case LE_SCAN_ENABLE:
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
|
||||
hci_dev_unlock(hdev);
|
||||
break;
|
||||
|
||||
case LE_SCAN_DISABLE:
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_stop_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
|
||||
hdev->discovery.state == DISCOVERY_FINDING) {
|
||||
mgmt_interleaved_discovery(hdev);
|
||||
} else {
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1077,18 +1030,10 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
|
||||
if (status) {
|
||||
hci_conn_check_pending(hdev);
|
||||
hci_dev_lock(hdev);
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(HCI_INQUIRY, &hdev->flags);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
|
||||
@ -2298,10 +2243,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_user_passkey_neg_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_PARAM:
|
||||
hci_cc_le_set_scan_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_ADV_ENABLE:
|
||||
hci_cc_le_set_adv_enable(hdev, skb);
|
||||
break;
|
||||
@ -2670,7 +2611,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
|
||||
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
@ -2746,7 +2687,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_conn_drop(conn);
|
||||
}
|
||||
|
||||
if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
|
||||
ev->key_type, pin_len);
|
||||
|
||||
|
@ -76,25 +76,19 @@ static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo
|
||||
ci->flags = session->flags;
|
||||
ci->state = BT_CONNECTED;
|
||||
|
||||
ci->vendor = 0x0000;
|
||||
ci->product = 0x0000;
|
||||
ci->version = 0x0000;
|
||||
|
||||
if (session->input) {
|
||||
ci->vendor = session->input->id.vendor;
|
||||
ci->product = session->input->id.product;
|
||||
ci->version = session->input->id.version;
|
||||
if (session->input->name)
|
||||
strncpy(ci->name, session->input->name, 128);
|
||||
strlcpy(ci->name, session->input->name, 128);
|
||||
else
|
||||
strncpy(ci->name, "HID Boot Device", 128);
|
||||
}
|
||||
|
||||
if (session->hid) {
|
||||
strlcpy(ci->name, "HID Boot Device", 128);
|
||||
} else if (session->hid) {
|
||||
ci->vendor = session->hid->vendor;
|
||||
ci->product = session->hid->product;
|
||||
ci->version = session->hid->version;
|
||||
strncpy(ci->name, session->hid->name, 128);
|
||||
strlcpy(ci->name, session->hid->name, 128);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,8 +504,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
|
||||
if (conn->hcon->type == LE_LINK) {
|
||||
/* LE connection */
|
||||
chan->omtu = L2CAP_DEFAULT_MTU;
|
||||
chan->scid = L2CAP_CID_LE_DATA;
|
||||
chan->dcid = L2CAP_CID_LE_DATA;
|
||||
if (chan->dcid == L2CAP_CID_ATT)
|
||||
chan->scid = L2CAP_CID_ATT;
|
||||
else
|
||||
chan->scid = l2cap_alloc_cid(conn);
|
||||
} else {
|
||||
/* Alloc CID for connection-oriented socket */
|
||||
chan->scid = l2cap_alloc_cid(conn);
|
||||
@ -543,6 +545,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
|
||||
|
||||
l2cap_chan_hold(chan);
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
|
||||
list_add(&chan->list, &conn->chan_l);
|
||||
}
|
||||
|
||||
@ -1338,17 +1342,21 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
|
||||
|
||||
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
struct sock *parent, *sk;
|
||||
struct sock *parent;
|
||||
struct l2cap_chan *chan, *pchan;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
/* Check if we have socket listening on cid */
|
||||
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
|
||||
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
|
||||
conn->src, conn->dst);
|
||||
if (!pchan)
|
||||
return;
|
||||
|
||||
/* Client ATT sockets should override the server one */
|
||||
if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
|
||||
return;
|
||||
|
||||
parent = pchan->sk;
|
||||
|
||||
lock_sock(parent);
|
||||
@ -1357,17 +1365,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
||||
if (!chan)
|
||||
goto clean;
|
||||
|
||||
sk = chan->sk;
|
||||
chan->dcid = L2CAP_CID_ATT;
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
bacpy(&bt_sk(chan->sk)->src, conn->src);
|
||||
bacpy(&bt_sk(chan->sk)->dst, conn->dst);
|
||||
|
||||
bacpy(&bt_sk(sk)->src, conn->src);
|
||||
bacpy(&bt_sk(sk)->dst, conn->dst);
|
||||
|
||||
l2cap_chan_add(conn, chan);
|
||||
|
||||
l2cap_chan_ready(chan);
|
||||
__l2cap_chan_add(conn, chan);
|
||||
|
||||
clean:
|
||||
release_sock(parent);
|
||||
@ -1380,14 +1383,17 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!hcon->out && hcon->type == LE_LINK)
|
||||
l2cap_le_conn_ready(conn);
|
||||
|
||||
/* For outgoing pairing which doesn't necessarily have an
|
||||
* associated socket (e.g. mgmt_pair_device).
|
||||
*/
|
||||
if (hcon->out && hcon->type == LE_LINK)
|
||||
smp_conn_security(hcon, hcon->pending_sec_level);
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
if (hcon->type == LE_LINK)
|
||||
l2cap_le_conn_ready(conn);
|
||||
|
||||
list_for_each_entry(chan, &conn->chan_l, list) {
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
@ -1792,7 +1798,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
|
||||
auth_type = l2cap_get_auth_type(chan);
|
||||
|
||||
if (chan->dcid == L2CAP_CID_LE_DATA)
|
||||
if (bdaddr_type_is_le(dst_type))
|
||||
hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
|
||||
chan->sec_level, auth_type);
|
||||
else
|
||||
@ -1811,16 +1817,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hcon->type == LE_LINK) {
|
||||
err = 0;
|
||||
|
||||
if (!list_empty(&conn->chan_l)) {
|
||||
err = -EBUSY;
|
||||
hci_conn_drop(hcon);
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto done;
|
||||
if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
|
||||
hci_conn_drop(hcon);
|
||||
err = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Update source addr of the socket */
|
||||
@ -1830,6 +1830,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
l2cap_chan_add(conn, chan);
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
/* l2cap_chan_add takes its own ref so we can drop this one */
|
||||
hci_conn_drop(hcon);
|
||||
|
||||
l2cap_state_change(chan, BT_CONNECT);
|
||||
__set_chan_timer(chan, sk->sk_sndtimeo);
|
||||
|
||||
@ -3751,8 +3754,6 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
|
||||
|
||||
sk = chan->sk;
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
|
||||
bacpy(&bt_sk(sk)->src, conn->src);
|
||||
bacpy(&bt_sk(sk)->dst, conn->dst);
|
||||
chan->psm = psm;
|
||||
@ -5292,6 +5293,51 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u8 *data = skb->data;
|
||||
int len = skb->len;
|
||||
struct l2cap_cmd_hdr cmd;
|
||||
int err;
|
||||
|
||||
l2cap_raw_recv(conn, skb);
|
||||
|
||||
while (len >= L2CAP_CMD_HDR_SIZE) {
|
||||
u16 cmd_len;
|
||||
memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
|
||||
data += L2CAP_CMD_HDR_SIZE;
|
||||
len -= L2CAP_CMD_HDR_SIZE;
|
||||
|
||||
cmd_len = le16_to_cpu(cmd.len);
|
||||
|
||||
BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len,
|
||||
cmd.ident);
|
||||
|
||||
if (cmd_len > len || !cmd.ident) {
|
||||
BT_DBG("corrupted command");
|
||||
break;
|
||||
}
|
||||
|
||||
err = l2cap_le_sig_cmd(conn, &cmd, data);
|
||||
if (err) {
|
||||
struct l2cap_cmd_rej_unk rej;
|
||||
|
||||
BT_ERR("Wrong link type (%d)", err);
|
||||
|
||||
/* FIXME: Map err to a valid reason */
|
||||
rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
|
||||
l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
|
||||
sizeof(rej), &rej);
|
||||
}
|
||||
|
||||
data += cmd_len;
|
||||
len -= cmd_len;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static inline void l2cap_sig_channel(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -5318,11 +5364,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
|
||||
break;
|
||||
}
|
||||
|
||||
if (conn->hcon->type == LE_LINK)
|
||||
err = l2cap_le_sig_cmd(conn, &cmd, data);
|
||||
else
|
||||
err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
|
||||
|
||||
err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
|
||||
if (err) {
|
||||
struct l2cap_cmd_rej_unk rej;
|
||||
|
||||
@ -6356,16 +6398,13 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
chan = l2cap_global_chan_by_scid(0, L2CAP_CID_LE_DATA,
|
||||
chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
|
||||
conn->src, conn->dst);
|
||||
if (!chan)
|
||||
goto drop;
|
||||
|
||||
BT_DBG("chan %p, len %d", chan, skb->len);
|
||||
|
||||
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
|
||||
goto drop;
|
||||
|
||||
if (chan->imtu < skb->len)
|
||||
goto drop;
|
||||
|
||||
@ -6395,6 +6434,8 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
switch (cid) {
|
||||
case L2CAP_CID_LE_SIGNALING:
|
||||
l2cap_le_sig_channel(conn, skb);
|
||||
break;
|
||||
case L2CAP_CID_SIGNALING:
|
||||
l2cap_sig_channel(conn, skb);
|
||||
break;
|
||||
@ -6405,7 +6446,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
l2cap_conless_channel(conn, psm, skb);
|
||||
break;
|
||||
|
||||
case L2CAP_CID_LE_DATA:
|
||||
case L2CAP_CID_ATT:
|
||||
l2cap_att_channel(conn, skb);
|
||||
break;
|
||||
|
||||
@ -6531,7 +6572,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chan->scid == L2CAP_CID_LE_DATA) {
|
||||
if (chan->scid == L2CAP_CID_ATT) {
|
||||
if (!status && encrypt) {
|
||||
chan->sec_level = hcon->sec_level;
|
||||
l2cap_chan_ready(chan);
|
||||
|
@ -466,7 +466,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
|
||||
{
|
||||
switch (chan->scid) {
|
||||
case L2CAP_CID_LE_DATA:
|
||||
case L2CAP_CID_ATT:
|
||||
if (mtu < L2CAP_LE_MIN_MTU)
|
||||
return false;
|
||||
break;
|
||||
@ -630,7 +630,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
conn = chan->conn;
|
||||
|
||||
/*change security for LE channels */
|
||||
if (chan->scid == L2CAP_CID_LE_DATA) {
|
||||
if (chan->scid == L2CAP_CID_ATT) {
|
||||
if (!conn->hcon->out) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
@ -102,18 +102,6 @@ static const u16 mgmt_events[] = {
|
||||
MGMT_EV_PASSKEY_NOTIFY,
|
||||
};
|
||||
|
||||
/*
|
||||
* These LE scan and inquiry parameters were chosen according to LE General
|
||||
* Discovery Procedure specification.
|
||||
*/
|
||||
#define LE_SCAN_WIN 0x12
|
||||
#define LE_SCAN_INT 0x12
|
||||
#define LE_SCAN_TIMEOUT_LE_ONLY msecs_to_jiffies(10240)
|
||||
#define LE_SCAN_TIMEOUT_BREDR_LE msecs_to_jiffies(5120)
|
||||
|
||||
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
|
||||
#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
|
||||
|
||||
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
|
||||
|
||||
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
|
||||
@ -1748,8 +1736,6 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
|
||||
hci_link_keys_clear(hdev);
|
||||
|
||||
set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
|
||||
|
||||
if (cp->debug_keys)
|
||||
set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
|
||||
else
|
||||
@ -2633,28 +2619,72 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
int mgmt_interleaved_discovery(struct hci_dev *hdev)
|
||||
static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
u8 type;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
|
||||
if (!cmd)
|
||||
return -ENOENT;
|
||||
|
||||
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
|
||||
if (err < 0)
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
type = hdev->discovery.type;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
|
||||
&type, sizeof(type));
|
||||
mgmt_pending_remove(cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void start_discovery_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
BT_DBG("status %d", status);
|
||||
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
switch (hdev->discovery.type) {
|
||||
case DISCOV_TYPE_LE:
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||
DISCOV_LE_TIMEOUT);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
|
||||
DISCOV_INTERLEAVED_TIMEOUT);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_BREDR:
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Invalid discovery type %d", hdev->discovery.type);
|
||||
}
|
||||
}
|
||||
|
||||
static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
void *data, u16 len)
|
||||
{
|
||||
struct mgmt_cp_start_discovery *cp = data;
|
||||
struct pending_cmd *cmd;
|
||||
struct hci_cp_le_set_scan_param param_cp;
|
||||
struct hci_cp_le_set_scan_enable enable_cp;
|
||||
struct hci_cp_inquiry inq_cp;
|
||||
struct hci_request req;
|
||||
/* General inquiry access code (GIAC) */
|
||||
u8 lap[3] = { 0x33, 0x8b, 0x9e };
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -2687,6 +2717,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
|
||||
hdev->discovery.type = cp->type;
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
switch (hdev->discovery.type) {
|
||||
case DISCOV_TYPE_BREDR:
|
||||
if (!lmp_bredr_capable(hdev)) {
|
||||
@ -2696,10 +2728,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
|
||||
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
||||
MGMT_STATUS_BUSY);
|
||||
mgmt_pending_remove(cmd);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
|
||||
memset(&inq_cp, 0, sizeof(inq_cp));
|
||||
memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
|
||||
inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
|
||||
hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_LE:
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
@ -2707,20 +2752,40 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
|
||||
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
|
||||
break;
|
||||
|
||||
case DISCOV_TYPE_INTERLEAVED:
|
||||
if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
|
||||
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
|
||||
!lmp_bredr_capable(hdev)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
mgmt_pending_remove(cmd);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
|
||||
LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
|
||||
if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
||||
MGMT_STATUS_REJECTED);
|
||||
mgmt_pending_remove(cmd);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
||||
MGMT_STATUS_BUSY);
|
||||
mgmt_pending_remove(cmd);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memset(¶m_cp, 0, sizeof(param_cp));
|
||||
param_cp.type = LE_SCAN_ACTIVE;
|
||||
param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
|
||||
param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
|
||||
hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
|
||||
¶m_cp);
|
||||
|
||||
memset(&enable_cp, 0, sizeof(enable_cp));
|
||||
enable_cp.enable = LE_SCAN_ENABLE;
|
||||
enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
|
||||
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
|
||||
&enable_cp);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2730,6 +2795,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = hci_req_run(&req, start_discovery_complete);
|
||||
if (err < 0)
|
||||
mgmt_pending_remove(cmd);
|
||||
else
|
||||
@ -2740,6 +2806,39 @@ failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
static 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_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
|
||||
&hdev->discovery.type, sizeof(hdev->discovery.type));
|
||||
mgmt_pending_remove(cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
BT_DBG("status %d", status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (status) {
|
||||
mgmt_stop_discovery_failed(hdev, status);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
u16 len)
|
||||
{
|
||||
@ -2747,6 +2846,8 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
struct pending_cmd *cmd;
|
||||
struct hci_cp_remote_name_req_cancel cp;
|
||||
struct inquiry_entry *e;
|
||||
struct hci_request req;
|
||||
struct hci_cp_le_set_scan_enable enable_cp;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -2773,12 +2874,20 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
switch (hdev->discovery.state) {
|
||||
case DISCOVERY_FINDING:
|
||||
if (test_bit(HCI_INQUIRY, &hdev->flags))
|
||||
err = hci_cancel_inquiry(hdev);
|
||||
else
|
||||
err = hci_cancel_le_scan(hdev);
|
||||
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
|
||||
hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
||||
} else {
|
||||
cancel_delayed_work(&hdev->le_scan_disable);
|
||||
|
||||
memset(&enable_cp, 0, sizeof(enable_cp));
|
||||
enable_cp.enable = LE_SCAN_DISABLE;
|
||||
hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
|
||||
sizeof(enable_cp), &enable_cp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -2796,16 +2905,22 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
}
|
||||
|
||||
bacpy(&cp.bdaddr, &e->data.bdaddr);
|
||||
err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
|
||||
sizeof(cp), &cp);
|
||||
hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
|
||||
&cp);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("unknown discovery state %u", hdev->discovery.state);
|
||||
err = -EFAULT;
|
||||
|
||||
mgmt_pending_remove(cmd);
|
||||
err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
|
||||
MGMT_STATUS_FAILED, &mgmt_cp->type,
|
||||
sizeof(mgmt_cp->type));
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
err = hci_req_run(&req, stop_discovery_complete);
|
||||
if (err < 0)
|
||||
mgmt_pending_remove(cmd);
|
||||
else
|
||||
@ -4063,6 +4178,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
struct mgmt_ev_device_found *ev = (void *) buf;
|
||||
size_t ev_size;
|
||||
|
||||
if (!hci_discovery_active(hdev))
|
||||
return -EPERM;
|
||||
|
||||
/* Leave 5 bytes for a potential CoD field */
|
||||
if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
|
||||
return -EINVAL;
|
||||
@ -4114,43 +4232,6 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
sizeof(*ev) + eir_len, NULL);
|
||||
}
|
||||
|
||||
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
u8 type;
|
||||
int err;
|
||||
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
|
||||
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
|
||||
if (!cmd)
|
||||
return -ENOENT;
|
||||
|
||||
type = hdev->discovery.type;
|
||||
|
||||
err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
|
||||
&type, sizeof(type));
|
||||
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_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
|
||||
&hdev->discovery.type, sizeof(hdev->discovery.type));
|
||||
mgmt_pending_remove(cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
|
||||
{
|
||||
struct mgmt_ev_discovering ev;
|
||||
|
Loading…
Reference in New Issue
Block a user