diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1ab94960764e9c29f533732892ec0ffdd0def9b7..586f69d084a2a0d1ec4868cf035ff449633671bf 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -783,6 +783,12 @@ extern struct mutex hci_cb_list_lock; hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); \ } while (0) +#define hci_dev_le_state_simultaneous(hdev) \ + (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) && \ + (hdev->le_states[4] & 0x08) && /* Central */ \ + (hdev->le_states[4] & 0x40) && /* Peripheral */ \ + (hdev->le_states[3] & 0x10)) /* Simultaneous */ + /* ----- HCI interface to upper protocols ----- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); int l2cap_disconn_ind(struct hci_conn *hcon); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 8c50a12ba5f5c9166d09595dbed1477604b3e4c4..61d8a076a3f3b58c8dc6fe348851a047213ff502 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5195,30 +5195,29 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn) 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 we're active scanning and the controller doesn't support + * simultaneous roles simply reject the attempt. */ if (hci_dev_test_flag(hdev, HCI_LE_SCAN) && - hdev->le_scan_type == LE_SCAN_ACTIVE) { + hdev->le_scan_type == LE_SCAN_ACTIVE && + !hci_dev_le_state_simultaneous(hdev)) { hci_conn_del(conn); return -EBUSY; } + /* Pause advertising while doing directed advertising. */ + hci_pause_advertising_sync(hdev); + err = hci_le_directed_advertising_sync(hdev, conn); goto done; } + /* Disable advertising if simultaneous roles is not supported. */ + if (!hci_dev_le_state_simultaneous(hdev)) + hci_pause_advertising_sync(hdev); + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { conn->le_conn_min_interval = params->conn_min_interval; @@ -5276,6 +5275,7 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn) HCI_CMD_TIMEOUT, NULL); done: + /* Re-enable advertising after the connection attempt is finished. */ hci_resume_advertising_sync(hdev); return err; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 962bb747d2cd086a1b7fd3af145f28fa59849c20..3326d9459dd3784400ebd89aa06a4a21481672fa 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3916,10 +3916,7 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, #endif if (hdev) { - if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) && - (hdev->le_states[4] & 0x08) && /* Central */ - (hdev->le_states[4] & 0x40) && /* Peripheral */ - (hdev->le_states[3] & 0x10)) /* Simultaneous */ + if (hci_dev_le_state_simultaneous(hdev)) flags = BIT(0); else flags = 0;