Skip to content

Commit

Permalink
Bluetooth: hci_sync: Add hci_le_create_conn_sync
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Luiz Augusto von Dentz authored and Marcel Holtmann committed Dec 22, 2021
1 parent fee6450 commit 8e8b92e
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 349 deletions.
3 changes: 1 addition & 2 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions include/net/bluetooth/hci_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
305 changes: 14 additions & 291 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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);
}

Expand Down
6 changes: 3 additions & 3 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 8e8b92e

Please sign in to comment.