Bluetooth: hci_sync: Add hci_le_create_conn_sync
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 22 Dec 2021 20:21:56 +0000 (12:21 -0800)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 22 Dec 2021 22:01:35 +0000 (23:01 +0100)
This adds hci_le_create_conn_sync and make hci_le_connect use it instead
of queueing multiple commands which may conflict with the likes of
hci_update_passive_scan which uses hci_cmd_sync_queue.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_sync.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/hci_request.c
net/bluetooth/hci_request.h
net/bluetooth/hci_sync.c
net/bluetooth/l2cap_core.c

index 6509109..1ab9496 100644 (file)
@@ -1121,8 +1121,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
                                     enum conn_reasons conn_reason);
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                                u8 dst_type, bool dst_resolved, u8 sec_level,
-                               u16 conn_timeout, u8 role,
-                               bdaddr_t *direct_rpa);
+                               u16 conn_timeout, u8 role);
 struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
                                 u8 sec_level, u8 auth_type,
                                 enum conn_reasons conn_reason);
index 435674c..2492e3b 100644 (file)
@@ -102,3 +102,7 @@ int hci_stop_discovery_sync(struct hci_dev *hdev);
 
 int hci_suspend_sync(struct hci_dev *hdev);
 int hci_resume_sync(struct hci_dev *hdev);
+
+struct hci_conn;
+
+int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
index cd6e1cf..04ebe90 100644 (file)
@@ -911,267 +911,45 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
        hci_enable_advertising(hdev);
 }
 
-static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct hci_conn *conn;
+       struct hci_conn *conn = data;
 
        hci_dev_lock(hdev);
 
-       conn = hci_lookup_le_connect(hdev);
-
-       if (hdev->adv_instance_cnt)
-               hci_req_resume_adv_instances(hdev);
-
-       if (!status) {
+       if (!err) {
                hci_connect_le_scan_cleanup(conn);
                goto done;
        }
 
-       bt_dev_err(hdev, "request failed to create LE connection: "
-                  "status 0x%2.2x", status);
+       bt_dev_err(hdev, "request failed to create LE connection: err %d", err);
 
        if (!conn)
                goto done;
 
-       hci_le_conn_failed(conn, status);
+       hci_le_conn_failed(conn, err);
 
 done:
        hci_dev_unlock(hdev);
 }
 
-static bool conn_use_rpa(struct hci_conn *conn)
-{
-       struct hci_dev *hdev = conn->hdev;
-
-       return hci_dev_test_flag(hdev, HCI_PRIVACY);
-}
-
-static void set_ext_conn_params(struct hci_conn *conn,
-                               struct hci_cp_le_ext_conn_param *p)
-{
-       struct hci_dev *hdev = conn->hdev;
-
-       memset(p, 0, sizeof(*p));
-
-       p->scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
-       p->scan_window = cpu_to_le16(hdev->le_scan_window_connect);
-       p->conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
-       p->conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
-       p->conn_latency = cpu_to_le16(conn->le_conn_latency);
-       p->supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
-       p->min_ce_len = cpu_to_le16(0x0000);
-       p->max_ce_len = cpu_to_le16(0x0000);
-}
-
-static void hci_req_add_le_create_conn(struct hci_request *req,
-                                      struct hci_conn *conn,
-                                      bdaddr_t *direct_rpa)
-{
-       struct hci_dev *hdev = conn->hdev;
-       u8 own_addr_type;
-
-       /* If direct address was provided we use it instead of current
-        * address.
-        */
-       if (direct_rpa) {
-               if (bacmp(&req->hdev->random_addr, direct_rpa))
-                       hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
-                                                               direct_rpa);
-
-               /* direct address is always RPA */
-               own_addr_type = ADDR_LE_DEV_RANDOM;
-       } else {
-               /* Update random address, but set require_privacy to false so
-                * that we never connect with an non-resolvable address.
-                */
-               if (hci_update_random_address(req, false, conn_use_rpa(conn),
-                                             &own_addr_type))
-                       return;
-       }
-
-       if (use_ext_conn(hdev)) {
-               struct hci_cp_le_ext_create_conn *cp;
-               struct hci_cp_le_ext_conn_param *p;
-               u8 data[sizeof(*cp) + sizeof(*p) * 3];
-               u32 plen;
-
-               cp = (void *) data;
-               p = (void *) cp->data;
-
-               memset(cp, 0, sizeof(*cp));
-
-               bacpy(&cp->peer_addr, &conn->dst);
-               cp->peer_addr_type = conn->dst_type;
-               cp->own_addr_type = own_addr_type;
-
-               plen = sizeof(*cp);
-
-               if (scan_1m(hdev)) {
-                       cp->phys |= LE_SCAN_PHY_1M;
-                       set_ext_conn_params(conn, p);
-
-                       p++;
-                       plen += sizeof(*p);
-               }
-
-               if (scan_2m(hdev)) {
-                       cp->phys |= LE_SCAN_PHY_2M;
-                       set_ext_conn_params(conn, p);
-
-                       p++;
-                       plen += sizeof(*p);
-               }
-
-               if (scan_coded(hdev)) {
-                       cp->phys |= LE_SCAN_PHY_CODED;
-                       set_ext_conn_params(conn, p);
-
-                       plen += sizeof(*p);
-               }
-
-               hci_req_add(req, HCI_OP_LE_EXT_CREATE_CONN, plen, data);
-
-       } else {
-               struct hci_cp_le_create_conn cp;
-
-               memset(&cp, 0, sizeof(cp));
-
-               cp.scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
-               cp.scan_window = cpu_to_le16(hdev->le_scan_window_connect);
-
-               bacpy(&cp.peer_addr, &conn->dst);
-               cp.peer_addr_type = conn->dst_type;
-               cp.own_address_type = own_addr_type;
-               cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
-               cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
-               cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
-               cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
-               cp.min_ce_len = cpu_to_le16(0x0000);
-               cp.max_ce_len = cpu_to_le16(0x0000);
-
-               hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
-       }
-
-       conn->state = BT_CONNECT;
-       clear_bit(HCI_CONN_SCANNING, &conn->flags);
-}
-
-static void hci_req_directed_advertising(struct hci_request *req,
-                                        struct hci_conn *conn)
+static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
 {
-       struct hci_dev *hdev = req->hdev;
-       u8 own_addr_type;
-       u8 enable;
-
-       if (ext_adv_capable(hdev)) {
-               struct hci_cp_le_set_ext_adv_params cp;
-               bdaddr_t random_addr;
-
-               /* Set require_privacy to false so that the remote device has a
-                * chance of identifying us.
-                */
-               if (hci_get_random_address(hdev, false, conn_use_rpa(conn), NULL,
-                                          &own_addr_type, &random_addr) < 0)
-                       return;
-
-               memset(&cp, 0, sizeof(cp));
-
-               cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_DIRECT_IND);
-               cp.own_addr_type = own_addr_type;
-               cp.channel_map = hdev->le_adv_channel_map;
-               cp.tx_power = HCI_TX_POWER_INVALID;
-               cp.primary_phy = HCI_ADV_PHY_1M;
-               cp.secondary_phy = HCI_ADV_PHY_1M;
-               cp.handle = 0; /* Use instance 0 for directed adv */
-               cp.own_addr_type = own_addr_type;
-               cp.peer_addr_type = conn->dst_type;
-               bacpy(&cp.peer_addr, &conn->dst);
-
-               /* As per Core Spec 5.2 Vol 2, PART E, Sec 7.8.53, for
-                * advertising_event_property LE_LEGACY_ADV_DIRECT_IND
-                * does not supports advertising data when the advertising set already
-                * contains some, the controller shall return erroc code 'Invalid
-                * HCI Command Parameters(0x12).
-                * So it is required to remove adv set for handle 0x00. since we use
-                * instance 0 for directed adv.
-                */
-               __hci_req_remove_ext_adv_instance(req, cp.handle);
-
-               hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(cp), &cp);
+       struct hci_conn *conn = data;
 
-               if (own_addr_type == ADDR_LE_DEV_RANDOM &&
-                   bacmp(&random_addr, BDADDR_ANY) &&
-                   bacmp(&random_addr, &hdev->random_addr)) {
-                       struct hci_cp_le_set_adv_set_rand_addr cp;
-
-                       memset(&cp, 0, sizeof(cp));
-
-                       cp.handle = 0;
-                       bacpy(&cp.bdaddr, &random_addr);
-
-                       hci_req_add(req,
-                                   HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
-                                   sizeof(cp), &cp);
-               }
-
-               __hci_req_enable_ext_advertising(req, 0x00);
-       } else {
-               struct hci_cp_le_set_adv_param cp;
+       bt_dev_dbg(hdev, "conn %p", conn);
 
-               /* Clear the HCI_LE_ADV 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.
-                */
-               hci_dev_clear_flag(hdev, HCI_LE_ADV);
-
-               /* Set require_privacy to false so that the remote device has a
-                * chance of identifying us.
-                */
-               if (hci_update_random_address(req, false, conn_use_rpa(conn),
-                                             &own_addr_type) < 0)
-                       return;
-
-               memset(&cp, 0, sizeof(cp));
-
-               /* Some controllers might reject command if intervals are not
-                * within range for undirected advertising.
-                * BCM20702A0 is known to be affected by this.
-                */
-               cp.min_interval = cpu_to_le16(0x0020);
-               cp.max_interval = cpu_to_le16(0x0020);
-
-               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;
+       return hci_le_create_conn_sync(hdev, conn);
 }
 
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
                                u8 dst_type, bool dst_resolved, u8 sec_level,
-                               u16 conn_timeout, u8 role, bdaddr_t *direct_rpa)
+                               u16 conn_timeout, u8 role)
 {
-       struct hci_conn_params *params;
        struct hci_conn *conn;
        struct smp_irk *irk;
-       struct hci_request req;
        int err;
 
-       /* This ensures that during disable le_scan address resolution
-        * will not be disabled if it is followed by le_create_conn
-        */
-       bool rpa_le_conn = true;
-
        /* Let's make sure that le is enabled.*/
        if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
                if (lmp_le_capable(hdev))
@@ -1230,68 +1008,13 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
        conn->sec_level = BT_SECURITY_LOW;
        conn->conn_timeout = conn_timeout;
 
-       hci_req_init(&req, hdev);
-
-       /* Disable advertising if we're active. For central role
-        * connections most controllers will refuse to connect if
-        * advertising is enabled, and for peripheral role connections we
-        * anyway have to disable it in order to start directed
-        * advertising. Any registered advertisements will be
-        * re-enabled after the connection attempt is finished.
-        */
-       if (hci_dev_test_flag(hdev, HCI_LE_ADV))
-               __hci_req_pause_adv_instances(&req);
-
-       /* If requested to connect as peripheral use directed advertising */
-       if (conn->role == HCI_ROLE_SLAVE) {
-               /* If we're active scanning most controllers are unable
-                * to initiate advertising. Simply reject the attempt.
-                */
-               if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
-                   hdev->le_scan_type == LE_SCAN_ACTIVE) {
-                       hci_req_purge(&req);
-                       hci_conn_del(conn);
-                       return ERR_PTR(-EBUSY);
-               }
-
-               hci_req_directed_advertising(&req, conn);
-               goto create_conn;
-       }
-
-       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
-       if (params) {
-               conn->le_conn_min_interval = params->conn_min_interval;
-               conn->le_conn_max_interval = params->conn_max_interval;
-               conn->le_conn_latency = params->conn_latency;
-               conn->le_supv_timeout = params->supervision_timeout;
-       } else {
-               conn->le_conn_min_interval = hdev->le_conn_min_interval;
-               conn->le_conn_max_interval = hdev->le_conn_max_interval;
-               conn->le_conn_latency = hdev->le_conn_latency;
-               conn->le_supv_timeout = hdev->le_supv_timeout;
-       }
-
-       /* 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
-        * handler for scan disabling knows to set the correct discovery
-        * state.
-        */
-       if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
-               hci_req_add_le_scan_disable(&req, rpa_le_conn);
-               hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
-       }
-
-       hci_req_add_le_create_conn(&req, conn, direct_rpa);
+       conn->state = BT_CONNECT;
+       clear_bit(HCI_CONN_SCANNING, &conn->flags);
 
-create_conn:
-       err = hci_req_run(&req, create_le_conn_complete);
+       err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, conn,
+                                create_le_conn_complete);
        if (err) {
                hci_conn_del(conn);
-
-               if (hdev->adv_instance_cnt)
-                       hci_req_resume_adv_instances(hdev);
-
                return ERR_PTR(err);
        }
 
index 240bffe..ca8e022 100644 (file)
@@ -5755,7 +5755,7 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
 static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
                                              bdaddr_t *addr,
                                              u8 addr_type, bool addr_resolved,
-                                             u8 adv_type, bdaddr_t *direct_rpa)
+                                             u8 adv_type)
 {
        struct hci_conn *conn;
        struct hci_conn_params *params;
@@ -5810,7 +5810,7 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
 
        conn = hci_connect_le(hdev, addr, addr_type, addr_resolved,
                              BT_SECURITY_LOW, hdev->def_le_autoconnect_timeout,
-                             HCI_ROLE_MASTER, direct_rpa);
+                             HCI_ROLE_MASTER);
        if (!IS_ERR(conn)) {
                /* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned
                 * by higher layer that tried to connect, if no then
@@ -5933,7 +5933,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
         * for advertising reports) and is already verified to be RPA above.
         */
        conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, bdaddr_resolved,
-                                    type, direct_addr);
+                                    type);
        if (!ext_adv && conn && type == LE_ADV_IND && len <= HCI_MAX_AD_LENGTH) {
                /* Store report for later inclusion by
                 * mgmt_device_connected
index ef5ced4..42c8047 100644 (file)
@@ -818,56 +818,6 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
        }
 }
 
-/* This function requires the caller holds hdev->lock */
-void __hci_req_pause_adv_instances(struct hci_request *req)
-{
-       bt_dev_dbg(req->hdev, "Pausing advertising instances");
-
-       /* Call to disable any advertisements active on the controller.
-        * This will succeed even if no advertisements are configured.
-        */
-       __hci_req_disable_advertising(req);
-
-       /* If we are using software rotation, pause the loop */
-       if (!ext_adv_capable(req->hdev))
-               cancel_adv_timeout(req->hdev);
-}
-
-/* This function requires the caller holds hdev->lock */
-static void __hci_req_resume_adv_instances(struct hci_request *req)
-{
-       struct adv_info *adv;
-
-       bt_dev_dbg(req->hdev, "Resuming advertising instances");
-
-       if (ext_adv_capable(req->hdev)) {
-               /* Call for each tracked instance to be re-enabled */
-               list_for_each_entry(adv, &req->hdev->adv_instances, list) {
-                       __hci_req_enable_ext_advertising(req,
-                                                        adv->instance);
-               }
-
-       } else {
-               /* Schedule for most recent instance to be restarted and begin
-                * the software rotation loop
-                */
-               __hci_req_schedule_adv_instance(req,
-                                               req->hdev->cur_adv_instance,
-                                               true);
-       }
-}
-
-/* This function requires the caller holds hdev->lock */
-int hci_req_resume_adv_instances(struct hci_dev *hdev)
-{
-       struct hci_request req;
-
-       hci_req_init(&req, hdev);
-       __hci_req_resume_adv_instances(&req);
-
-       return hci_req_run(&req, NULL);
-}
-
 static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
 {
        return hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance);
index 8d39e94..7f8df25 100644 (file)
@@ -80,8 +80,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req);
 void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next);
 
 void hci_req_disable_address_resolution(struct hci_dev *hdev);
-void __hci_req_pause_adv_instances(struct hci_request *req);
-int hci_req_resume_adv_instances(struct hci_dev *hdev);
 void hci_req_reenable_advertising(struct hci_dev *hdev);
 void __hci_req_enable_advertising(struct hci_request *req);
 void __hci_req_disable_advertising(struct hci_request *req);
index 2fb8bc4..a3cf848 100644 (file)
@@ -4999,3 +4999,280 @@ int hci_resume_sync(struct hci_dev *hdev)
 
        return 0;
 }
+
+static bool conn_use_rpa(struct hci_conn *conn)
+{
+       struct hci_dev *hdev = conn->hdev;
+
+       return hci_dev_test_flag(hdev, HCI_PRIVACY);
+}
+
+static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
+                                               struct hci_conn *conn)
+{
+       struct hci_cp_le_set_ext_adv_params cp;
+       int err;
+       bdaddr_t random_addr;
+       u8 own_addr_type;
+
+       err = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
+                                            &own_addr_type);
+       if (err)
+               return err;
+
+       /* Set require_privacy to false so that the remote device has a
+        * chance of identifying us.
+        */
+       err = hci_get_random_address(hdev, false, conn_use_rpa(conn), NULL,
+                                    &own_addr_type, &random_addr);
+       if (err)
+               return err;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_DIRECT_IND);
+       cp.own_addr_type = own_addr_type;
+       cp.channel_map = hdev->le_adv_channel_map;
+       cp.tx_power = HCI_TX_POWER_INVALID;
+       cp.primary_phy = HCI_ADV_PHY_1M;
+       cp.secondary_phy = HCI_ADV_PHY_1M;
+       cp.handle = 0x00; /* Use instance 0 for directed adv */
+       cp.own_addr_type = own_addr_type;
+       cp.peer_addr_type = conn->dst_type;
+       bacpy(&cp.peer_addr, &conn->dst);
+
+       /* As per Core Spec 5.2 Vol 2, PART E, Sec 7.8.53, for
+        * advertising_event_property LE_LEGACY_ADV_DIRECT_IND
+        * does not supports advertising data when the advertising set already
+        * contains some, the controller shall return erroc code 'Invalid
+        * HCI Command Parameters(0x12).
+        * So it is required to remove adv set for handle 0x00. since we use
+        * instance 0 for directed adv.
+        */
+       err = hci_remove_ext_adv_instance_sync(hdev, cp.handle, NULL);
+       if (err)
+               return err;
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (err)
+               return err;
+
+       /* Check if random address need to be updated */
+       if (own_addr_type == ADDR_LE_DEV_RANDOM &&
+           bacmp(&random_addr, BDADDR_ANY) &&
+           bacmp(&random_addr, &hdev->random_addr)) {
+               err = hci_set_adv_set_random_addr_sync(hdev, 0x00,
+                                                      &random_addr);
+               if (err)
+                       return err;
+       }
+
+       return hci_enable_ext_advertising_sync(hdev, 0x00);
+}
+
+static int hci_le_directed_advertising_sync(struct hci_dev *hdev,
+                                           struct hci_conn *conn)
+{
+       struct hci_cp_le_set_adv_param cp;
+       u8 status;
+       u8 own_addr_type;
+       u8 enable;
+
+       if (ext_adv_capable(hdev))
+               return hci_le_ext_directed_advertising_sync(hdev, conn);
+
+       /* Clear the HCI_LE_ADV 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.
+        */
+       hci_dev_clear_flag(hdev, HCI_LE_ADV);
+
+       /* Set require_privacy to false so that the remote device has a
+        * chance of identifying us.
+        */
+       status = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
+                                               &own_addr_type);
+       if (status)
+               return status;
+
+       memset(&cp, 0, sizeof(cp));
+
+       /* Some controllers might reject command if intervals are not
+        * within range for undirected advertising.
+        * BCM20702A0 is known to be affected by this.
+        */
+       cp.min_interval = cpu_to_le16(0x0020);
+       cp.max_interval = cpu_to_le16(0x0020);
+
+       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;
+
+       status = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_PARAM,
+                                      sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (status)
+               return status;
+
+       enable = 0x01;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
+                                    sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+}
+
+static void set_ext_conn_params(struct hci_conn *conn,
+                               struct hci_cp_le_ext_conn_param *p)
+{
+       struct hci_dev *hdev = conn->hdev;
+
+       memset(p, 0, sizeof(*p));
+
+       p->scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
+       p->scan_window = cpu_to_le16(hdev->le_scan_window_connect);
+       p->conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
+       p->conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
+       p->conn_latency = cpu_to_le16(conn->le_conn_latency);
+       p->supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
+       p->min_ce_len = cpu_to_le16(0x0000);
+       p->max_ce_len = cpu_to_le16(0x0000);
+}
+
+int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
+                               u8 own_addr_type)
+{
+       struct hci_cp_le_ext_create_conn *cp;
+       struct hci_cp_le_ext_conn_param *p;
+       u8 data[sizeof(*cp) + sizeof(*p) * 3];
+       u32 plen;
+
+       cp = (void *)data;
+       p = (void *)cp->data;
+
+       memset(cp, 0, sizeof(*cp));
+
+       bacpy(&cp->peer_addr, &conn->dst);
+       cp->peer_addr_type = conn->dst_type;
+       cp->own_addr_type = own_addr_type;
+
+       plen = sizeof(*cp);
+
+       if (scan_1m(hdev)) {
+               cp->phys |= LE_SCAN_PHY_1M;
+               set_ext_conn_params(conn, p);
+
+               p++;
+               plen += sizeof(*p);
+       }
+
+       if (scan_2m(hdev)) {
+               cp->phys |= LE_SCAN_PHY_2M;
+               set_ext_conn_params(conn, p);
+
+               p++;
+               plen += sizeof(*p);
+       }
+
+       if (scan_coded(hdev)) {
+               cp->phys |= LE_SCAN_PHY_CODED;
+               set_ext_conn_params(conn, p);
+
+               plen += sizeof(*p);
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_EXT_CREATE_CONN,
+                                    plen, data, HCI_CMD_TIMEOUT);
+}
+
+int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
+{
+       struct hci_cp_le_create_conn cp;
+       struct hci_conn_params *params;
+       u8 own_addr_type;
+       int err;
+
+       /* Disable advertising if we're active. For central role
+        * connections most controllers will refuse to connect if
+        * advertising is enabled, and for peripheral role connections we
+        * anyway have to disable it in order to start directed
+        * advertising. Any registered advertisements will be
+        * re-enabled after the connection attempt is finished.
+        */
+       hci_pause_advertising_sync(hdev);
+
+       /* If requested to connect as peripheral use directed advertising */
+       if (conn->role == HCI_ROLE_SLAVE) {
+               /* If we're active scanning most controllers are unable
+                * to initiate advertising. Simply reject the attempt.
+                */
+               if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
+                   hdev->le_scan_type == LE_SCAN_ACTIVE) {
+                       hci_conn_del(conn);
+                       return -EBUSY;
+               }
+
+               err = hci_le_directed_advertising_sync(hdev, conn);
+               goto done;
+       }
+
+       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+       if (params) {
+               conn->le_conn_min_interval = params->conn_min_interval;
+               conn->le_conn_max_interval = params->conn_max_interval;
+               conn->le_conn_latency = params->conn_latency;
+               conn->le_supv_timeout = params->supervision_timeout;
+       } else {
+               conn->le_conn_min_interval = hdev->le_conn_min_interval;
+               conn->le_conn_max_interval = hdev->le_conn_max_interval;
+               conn->le_conn_latency = hdev->le_conn_latency;
+               conn->le_supv_timeout = hdev->le_supv_timeout;
+       }
+
+       /* 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
+        * handler for scan disabling knows to set the correct discovery
+        * state.
+        */
+       if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
+               hci_scan_disable_sync(hdev);
+               hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
+       }
+
+       /* Update random address, but set require_privacy to false so
+        * that we never connect with an non-resolvable address.
+        */
+       err = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
+                                            &own_addr_type);
+       if (err)
+               goto done;
+
+       if (use_ext_conn(hdev)) {
+               err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
+               goto done;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
+       cp.scan_window = cpu_to_le16(hdev->le_scan_window_connect);
+
+       bacpy(&cp.peer_addr, &conn->dst);
+       cp.peer_addr_type = conn->dst_type;
+       cp.own_address_type = own_addr_type;
+       cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
+       cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
+       cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
+       cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
+       cp.min_ce_len = cpu_to_le16(0x0000);
+       cp.max_ce_len = cpu_to_le16(0x0000);
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+
+done:
+       hci_resume_advertising_sync(hdev);
+       return err;
+}
index 4f8f375..e817ff0 100644 (file)
@@ -7905,7 +7905,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                        hcon = hci_connect_le(hdev, dst, dst_type, false,
                                              chan->sec_level,
                                              HCI_LE_CONN_TIMEOUT,
-                                             HCI_ROLE_SLAVE, NULL);
+                                             HCI_ROLE_SLAVE);
                else
                        hcon = hci_connect_le_scan(hdev, dst, dst_type,
                                                   chan->sec_level,