Bluetooth: Store max TX power level for connection
[cascardo/linux.git] / net / bluetooth / hci_conn.c
index 129c22a..a987e7d 100644 (file)
@@ -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);
 }
 
@@ -393,6 +407,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        conn->io_capability = hdev->io_capability;
        conn->remote_auth = 0xff;
        conn->key_type = 0xff;
+       conn->tx_power = HCI_TX_POWER_INVALID;
+       conn->max_tx_power = HCI_TX_POWER_INVALID;
 
        set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -549,6 +565,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 +630,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 +678,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 +725,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 +748,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 +761,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);