|
@@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work)
|
|
|
{
|
|
|
struct hci_conn *conn = container_of(work, struct hci_conn,
|
|
|
le_conn_timeout.work);
|
|
|
+ struct hci_dev *hdev = conn->hdev;
|
|
|
|
|
|
BT_DBG("");
|
|
|
|
|
|
+ /* We could end up here due to having done directed advertising,
|
|
|
+ * so clean up the state if necessary. This should however only
|
|
|
+ * happen with broken hardware or if low duty cycle was used
|
|
|
+ * (which doesn't have a timeout of its own).
|
|
|
+ */
|
|
|
+ if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
|
|
|
+ u8 enable = 0x00;
|
|
|
+ hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
|
|
|
+ &enable);
|
|
|
+ hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
hci_le_create_connection_cancel(conn);
|
|
|
}
|
|
|
|
|
@@ -549,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
|
|
|
* favor of connection establishment, we should restart it.
|
|
|
*/
|
|
|
hci_update_background_scan(hdev);
|
|
|
+
|
|
|
+ /* Re-enable advertising in case this was a failed connection
|
|
|
+ * attempt as a peripheral.
|
|
|
+ */
|
|
|
+ mgmt_reenable_advertising(hdev);
|
|
|
}
|
|
|
|
|
|
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
|
@@ -609,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
|
|
|
conn->state = BT_CONNECT;
|
|
|
}
|
|
|
|
|
|
+static void hci_req_directed_advertising(struct hci_request *req,
|
|
|
+ struct hci_conn *conn)
|
|
|
+{
|
|
|
+ struct hci_dev *hdev = req->hdev;
|
|
|
+ struct hci_cp_le_set_adv_param cp;
|
|
|
+ u8 own_addr_type;
|
|
|
+ u8 enable;
|
|
|
+
|
|
|
+ enable = 0x00;
|
|
|
+ hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
|
|
+
|
|
|
+ /* Clear the HCI_ADVERTISING bit temporarily so that the
|
|
|
+ * hci_update_random_address knows that it's safe to go ahead
|
|
|
+ * and write a new random address. The flag will be set back on
|
|
|
+ * as soon as the SET_ADV_ENABLE HCI command completes.
|
|
|
+ */
|
|
|
+ clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
|
|
+
|
|
|
+ /* Set require_privacy to false so that the remote device has a
|
|
|
+ * chance of identifying us.
|
|
|
+ */
|
|
|
+ if (hci_update_random_address(req, false, &own_addr_type) < 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ memset(&cp, 0, sizeof(cp));
|
|
|
+ cp.type = LE_ADV_DIRECT_IND;
|
|
|
+ cp.own_address_type = own_addr_type;
|
|
|
+ cp.direct_addr_type = conn->dst_type;
|
|
|
+ bacpy(&cp.direct_addr, &conn->dst);
|
|
|
+ cp.channel_map = hdev->le_adv_channel_map;
|
|
|
+
|
|
|
+ hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
|
|
|
+
|
|
|
+ enable = 0x01;
|
|
|
+ hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
|
|
+
|
|
|
+ conn->state = BT_CONNECT;
|
|
|
+}
|
|
|
+
|
|
|
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|
|
u8 dst_type, u8 sec_level, u8 auth_type)
|
|
|
{
|
|
@@ -618,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|
|
struct hci_request req;
|
|
|
int err;
|
|
|
|
|
|
- if (test_bit(HCI_ADVERTISING, &hdev->flags))
|
|
|
- return ERR_PTR(-ENOTSUPP);
|
|
|
-
|
|
|
/* Some devices send ATT messages as soon as the physical link is
|
|
|
* established. To be able to handle these ATT messages, the user-
|
|
|
* space first establishes the connection and then starts the pairing
|
|
@@ -668,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
conn->dst_type = dst_type;
|
|
|
-
|
|
|
- conn->out = true;
|
|
|
- conn->link_mode |= HCI_LM_MASTER;
|
|
|
conn->sec_level = BT_SECURITY_LOW;
|
|
|
conn->pending_sec_level = sec_level;
|
|
|
conn->auth_type = auth_type;
|
|
|
|
|
|
+ hci_req_init(&req, hdev);
|
|
|
+
|
|
|
+ if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
|
|
|
+ hci_req_directed_advertising(&req, conn);
|
|
|
+ goto create_conn;
|
|
|
+ }
|
|
|
+
|
|
|
+ conn->out = true;
|
|
|
+ conn->link_mode |= HCI_LM_MASTER;
|
|
|
+
|
|
|
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
|
|
if (params) {
|
|
|
conn->le_conn_min_interval = params->conn_min_interval;
|
|
@@ -684,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|
|
conn->le_conn_max_interval = hdev->le_conn_max_interval;
|
|
|
}
|
|
|
|
|
|
- hci_req_init(&req, hdev);
|
|
|
-
|
|
|
/* If controller is scanning, we stop it since some controllers are
|
|
|
* not able to scan and connect at the same time. Also set the
|
|
|
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
|
|
@@ -699,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|
|
|
|
|
hci_req_add_le_create_conn(&req, conn);
|
|
|
|
|
|
+create_conn:
|
|
|
err = hci_req_run(&req, create_le_conn_complete);
|
|
|
if (err) {
|
|
|
hci_conn_del(conn);
|