Skip to content

Commit

Permalink
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/bluetooth/bluetooth

Johan Hedberg says:

====================
pull request: bluetooth 2015-10-16

First of all, sorry for the late set of patches for the 4.3 cycle. We
just finished an intensive week of testing at the Bluetooth UnPlugFest
and discovered (and fixed) issues there. Unfortunately a few issues
affect 4.3-rc5 in a way that they break existing Bluetooth LE mouse and
keyboard support.

The regressions result from supporting LE privacy in conjunction with
scanning for Resolvable Private Addresses before connecting. A feature
that has been tested heavily (including automated unit tests), but sadly
some regressions slipped in. The UnPlugFest with its multitude of test
platforms is a good battle testing ground for uncovering every corner
case.

The patches in this pull request focus only on fixing the regressions in
4.3-rc5. The patches look a bit larger since we also added comments in
the critical sections of the fixes to improve clarity.

I would appreciate if we can get these regression fixes to Linus
quickly. Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Oct 19, 2015
2 parents 833b8f1 + 5157b8a commit a5d6f7d
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 42 deletions.
99 changes: 71 additions & 28 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,64 @@ static void hci_connect_le_scan_cleanup(struct hci_conn *conn)
* autoconnect action, remove them completely. If they are, just unmark
* them as waiting for connection, by clearing explicit_connect field.
*/
if (params->auto_connect == HCI_AUTO_CONN_EXPLICIT)
params->explicit_connect = false;

list_del_init(&params->action);

switch (params->auto_connect) {
case HCI_AUTO_CONN_EXPLICIT:
hci_conn_params_del(conn->hdev, bdaddr, bdaddr_type);
else
params->explicit_connect = false;
/* return instead of break to avoid duplicate scan update */
return;
case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS:
list_add(&params->action, &conn->hdev->pend_le_conns);
break;
case HCI_AUTO_CONN_REPORT:
list_add(&params->action, &conn->hdev->pend_le_reports);
break;
default:
break;
}

hci_update_background_scan(conn->hdev);
}

static void hci_conn_cleanup(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;

if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);

hci_chan_list_flush(conn);

hci_conn_hash_del(hdev, conn);

if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);

hci_conn_del_sysfs(conn);

debugfs_remove_recursive(conn->debugfs);

hci_dev_put(hdev);

hci_conn_put(conn);
}

/* This function requires the caller holds hdev->lock */
static void hci_connect_le_scan_remove(struct hci_conn *conn)
{
hci_connect_le_scan_cleanup(conn);

hci_conn_hash_del(conn->hdev, conn);
hci_update_background_scan(conn->hdev);
/* We can't call hci_conn_del here since that would deadlock
* with trying to call cancel_delayed_work_sync(&conn->disc_work).
* Instead, call just hci_conn_cleanup() which contains the bare
* minimum cleanup operations needed for a connection in this
* state.
*/
hci_conn_cleanup(conn);
}

static void hci_acl_create_connection(struct hci_conn *conn)
Expand Down Expand Up @@ -581,27 +626,17 @@ int hci_conn_del(struct hci_conn *conn)
}
}

hci_chan_list_flush(conn);

if (conn->amp_mgr)
amp_mgr_put(conn->amp_mgr);

hci_conn_hash_del(hdev, conn);
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);

skb_queue_purge(&conn->data_q);

hci_conn_del_sysfs(conn);

debugfs_remove_recursive(conn->debugfs);

if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);

hci_dev_put(hdev);

hci_conn_put(conn);
/* Remove the connection from the list and cleanup its remaining
* state. This is a separate function since for some cases like
* BT_CONNECT_SCAN we *only* want the cleanup part without the
* rest of hci_conn_del.
*/
hci_conn_cleanup(conn);

return 0;
}
Expand Down Expand Up @@ -973,15 +1008,23 @@ static int hci_explicit_conn_params_set(struct hci_request *req,
if (is_connected(hdev, addr, addr_type))
return -EISCONN;

params = hci_conn_params_add(hdev, addr, addr_type);
if (!params)
return -EIO;
params = hci_conn_params_lookup(hdev, addr, addr_type);
if (!params) {
params = hci_conn_params_add(hdev, addr, addr_type);
if (!params)
return -ENOMEM;

/* If we created new params, or existing params were marked as disabled,
* mark them to be used just once to connect.
*/
if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
/* If we created new params, mark them to be deleted in
* hci_connect_le_scan_cleanup. It's different case than
* existing disabled params, those will stay after cleanup.
*/
params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
}

/* We're trying to connect, so make sure params are at pend_le_conns */
if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
params->auto_connect == HCI_AUTO_CONN_REPORT ||
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
list_del_init(&params->action);
list_add(&params->action, &hdev->pend_le_conns);
}
Expand Down
7 changes: 0 additions & 7 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2861,13 +2861,6 @@ struct hci_conn_params *hci_explicit_connect_lookup(struct hci_dev *hdev,
return param;
}

list_for_each_entry(param, &hdev->pend_le_reports, action) {
if (bacmp(&param->addr, addr) == 0 &&
param->addr_type == addr_type &&
param->explicit_connect)
return param;
}

return NULL;
}

Expand Down
11 changes: 8 additions & 3 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
wake_up_bit(&hdev->flags, HCI_INQUIRY);

hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
/* Set discovery state to stopped if we're not doing LE active
* scanning.
*/
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
hdev->le_scan_type != LE_SCAN_ACTIVE)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);

hci_conn_check_pending(hdev);
Expand Down Expand Up @@ -4648,8 +4653,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
/* If we're not connectable only connect devices that we have in
* our pend_le_conns list.
*/
params = hci_explicit_connect_lookup(hdev, addr, addr_type);

params = hci_pend_le_action_lookup(&hdev->pend_le_conns, addr,
addr_type);
if (!params)
return NULL;

Expand Down
24 changes: 20 additions & 4 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -3545,6 +3545,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
auth_type);
} else {
u8 addr_type;
struct hci_conn_params *p;

/* Convert from L2CAP channel address type to HCI address type
*/
Expand All @@ -3562,7 +3563,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
* If connection parameters already exist, then they
* will be kept and this function does nothing.
*/
hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);

if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
p->auto_connect = HCI_AUTO_CONN_DISABLED;

conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr,
addr_type, sec_level,
Expand Down Expand Up @@ -6117,14 +6121,21 @@ static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
__hci_update_background_scan(req);
break;
case HCI_AUTO_CONN_REPORT:
list_add(&params->action, &hdev->pend_le_reports);
if (params->explicit_connect)
list_add(&params->action, &hdev->pend_le_conns);
else
list_add(&params->action, &hdev->pend_le_reports);
__hci_update_background_scan(req);
break;
case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS:
if (!is_connected(hdev, addr, addr_type)) {
list_add(&params->action, &hdev->pend_le_conns);
__hci_update_background_scan(req);
/* If we are in scan phase of connecting, we were
* already added to pend_le_conns and scanning.
*/
if (params->auto_connect != HCI_AUTO_CONN_EXPLICIT)
__hci_update_background_scan(req);
}
break;
}
Expand Down Expand Up @@ -6379,7 +6390,8 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
err = cmd->cmd_complete(cmd,
MGMT_STATUS_INVALID_PARAMS);
mgmt_pending_remove(cmd);
Expand Down Expand Up @@ -6415,6 +6427,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
continue;
device_removed(sk, hdev, &p->addr, p->addr_type);
if (p->explicit_connect) {
p->auto_connect = HCI_AUTO_CONN_EXPLICIT;
continue;
}
list_del(&p->action);
list_del(&p->list);
kfree(p);
Expand Down

0 comments on commit a5d6f7d

Please sign in to comment.