Bluetooth: HCI: Add initial support for PAST
This adds PAST related commands (HCI_OP_LE_PAST, HCI_OP_LE_PAST_SET_INFO and HCI_OP_LE_PAST_PARAMS) and events (HCI_EV_LE_PAST_RECEIVED) along with handling of PAST sender and receiver features bits including new MGMG settings ( HCI_EV_LE_PAST_RECEIVED and MGMT_SETTING_PAST_RECEIVER) which userspace can use to determine if PAST is supported by the controller. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>pull/1354/merge
parent
97fdb2ea06
commit
33b2835f0b
|
|
@ -647,6 +647,8 @@ enum {
|
|||
#define HCI_LE_EXT_ADV 0x10
|
||||
#define HCI_LE_PERIODIC_ADV 0x20
|
||||
#define HCI_LE_CHAN_SEL_ALG2 0x40
|
||||
#define HCI_LE_PAST_SENDER 0x01
|
||||
#define HCI_LE_PAST_RECEIVER 0x02
|
||||
#define HCI_LE_CIS_CENTRAL 0x10
|
||||
#define HCI_LE_CIS_PERIPHERAL 0x20
|
||||
#define HCI_LE_ISO_BROADCASTER 0x40
|
||||
|
|
@ -2068,6 +2070,44 @@ struct hci_cp_le_set_privacy_mode {
|
|||
__u8 mode;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST 0x205a
|
||||
struct hci_cp_le_past {
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__le16 sync_handle;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST_SET_INFO 0x205b
|
||||
struct hci_cp_le_past_set_info {
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__u8 adv_handle;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past_set_info {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST_PARAMS 0x205c
|
||||
struct hci_cp_le_past_params {
|
||||
__le16 handle;
|
||||
__u8 mode;
|
||||
__le16 skip;
|
||||
__le16 sync_timeout;
|
||||
__u8 cte_type;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past_params {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060
|
||||
struct hci_rp_le_read_buffer_size_v2 {
|
||||
__u8 status;
|
||||
|
|
@ -2800,6 +2840,20 @@ struct hci_evt_le_ext_adv_set_term {
|
|||
__u8 num_evts;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_PAST_RECEIVED 0x18
|
||||
struct hci_ev_le_past_received {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__le16 sync_handle;
|
||||
__u8 sid;
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 phy;
|
||||
__le16 interval;
|
||||
__u8 clock_accuracy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_CIS_ESTABLISHED 0x19
|
||||
struct hci_evt_le_cis_established {
|
||||
__u8 status;
|
||||
|
|
|
|||
|
|
@ -2053,6 +2053,18 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
#define sync_recv_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_ISO_SYNC_RECEIVER)
|
||||
#define sync_recv_enabled(dev) (le_enabled(dev) && sync_recv_capable(dev))
|
||||
#define past_sender_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_PAST_SENDER)
|
||||
#define past_receiver_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_PAST_RECEIVER)
|
||||
#define past_capable(dev) \
|
||||
(past_sender_capable(dev) || past_receiver_capable(dev))
|
||||
#define past_sender_enabled(dev) \
|
||||
(le_enabled(dev) && past_sender_capable(dev))
|
||||
#define past_receiver_enabled(dev) \
|
||||
(le_enabled(dev) && past_receiver_capable(dev))
|
||||
#define past_enabled(dev) \
|
||||
(past_sender_enabled(dev) || past_receiver_enabled(dev))
|
||||
|
||||
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
|
||||
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ struct mgmt_rp_read_index_list {
|
|||
#define MGMT_SETTING_ISO_BROADCASTER BIT(20)
|
||||
#define MGMT_SETTING_ISO_SYNC_RECEIVER BIT(21)
|
||||
#define MGMT_SETTING_LL_PRIVACY BIT(22)
|
||||
#define MGMT_SETTING_PAST_SENDER BIT(23)
|
||||
#define MGMT_SETTING_PAST_RECEIVER BIT(24)
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
#define MGMT_READ_INFO_SIZE 0
|
||||
|
|
|
|||
|
|
@ -5936,6 +5936,71 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
||||
{
|
||||
struct hci_cp_le_pa_term_sync cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = handle;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_past_received_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_past_received *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
struct hci_conn *pa_sync, *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
||||
|
||||
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev,
|
||||
"Unable to find connection for dst %pMR sid 0x%2.2x",
|
||||
&ev->bdaddr, ev->sid);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn->sync_handle = le16_to_cpu(ev->sync_handle);
|
||||
conn->sid = HCI_SID_INVALID;
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, PA_LINK,
|
||||
&flags);
|
||||
if (!(mask & HCI_LM_ACCEPT)) {
|
||||
hci_le_pa_term_sync(hdev, ev->sync_handle);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(flags & HCI_PROTO_DEFER))
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
goto unlock;
|
||||
|
||||
pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
|
||||
|
||||
if (ev->status) {
|
||||
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
|
||||
|
||||
/* Notify iso layer */
|
||||
hci_connect_cfm(pa_sync, ev->status);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -6412,16 +6477,6 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
||||
{
|
||||
struct hci_cp_le_pa_term_sync cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = handle;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -7206,6 +7261,10 @@ static const struct hci_le_ev {
|
|||
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
|
||||
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
|
||||
sizeof(struct hci_evt_le_ext_adv_set_term)),
|
||||
/* [0x18 = HCI_EVT_LE_PAST_RECEIVED] */
|
||||
HCI_LE_EV(HCI_EV_LE_PAST_RECEIVED,
|
||||
hci_le_past_received_evt,
|
||||
sizeof(struct hci_ev_le_past_received)),
|
||||
/* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */
|
||||
HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_established_evt,
|
||||
sizeof(struct hci_evt_le_cis_established)),
|
||||
|
|
|
|||
|
|
@ -4393,6 +4393,9 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
|
|||
if (ext_adv_capable(hdev))
|
||||
events[2] |= 0x02; /* LE Advertising Set Terminated */
|
||||
|
||||
if (past_receiver_capable(hdev))
|
||||
events[2] |= 0x80; /* LE PAST Received */
|
||||
|
||||
if (cis_capable(hdev)) {
|
||||
events[3] |= 0x01; /* LE CIS Established */
|
||||
if (cis_peripheral_capable(hdev))
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ static struct bt_iso_qos default_qos;
|
|||
static bool check_ucast_qos(struct bt_iso_qos *qos);
|
||||
static bool check_bcast_qos(struct bt_iso_qos *qos);
|
||||
static bool iso_match_sid(struct sock *sk, void *data);
|
||||
static bool iso_match_sid_past(struct sock *sk, void *data);
|
||||
static bool iso_match_sync_handle(struct sock *sk, void *data);
|
||||
static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data);
|
||||
static void iso_sock_disconn(struct sock *sk);
|
||||
|
|
@ -2090,6 +2091,16 @@ static bool iso_match_sid(struct sock *sk, void *data)
|
|||
return ev->sid == iso_pi(sk)->bc_sid;
|
||||
}
|
||||
|
||||
static bool iso_match_sid_past(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_ev_le_past_received *ev = data;
|
||||
|
||||
if (iso_pi(sk)->bc_sid == HCI_SID_INVALID)
|
||||
return true;
|
||||
|
||||
return ev->sid == iso_pi(sk)->bc_sid;
|
||||
}
|
||||
|
||||
static bool iso_match_sync_handle(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_evt_le_big_info_adv_report *ev = data;
|
||||
|
|
@ -2109,6 +2120,7 @@ static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data)
|
|||
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
{
|
||||
struct hci_ev_le_pa_sync_established *ev1;
|
||||
struct hci_ev_le_past_received *ev1a;
|
||||
struct hci_evt_le_big_info_adv_report *ev2;
|
||||
struct hci_ev_le_per_adv_report *ev3;
|
||||
struct sock *sk;
|
||||
|
|
@ -2122,6 +2134,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
* SID to listen to and once sync is established its handle needs to
|
||||
* be stored in iso_pi(sk)->sync_handle so it can be matched once
|
||||
* receiving the BIG Info.
|
||||
* 1a. HCI_EV_LE_PAST_RECEIVED: alternative to 1.
|
||||
* 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a
|
||||
* a BIG Info it attempts to check if there any listening socket with
|
||||
* the same sync_handle and if it does then attempt to create a sync.
|
||||
|
|
@ -2141,6 +2154,18 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
goto done;
|
||||
}
|
||||
|
||||
ev1a = hci_recv_event_data(hdev, HCI_EV_LE_PAST_RECEIVED);
|
||||
if (ev1a) {
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
iso_match_sid_past, ev1a);
|
||||
if (sk && !ev1a->status) {
|
||||
iso_pi(sk)->sync_handle = le16_to_cpu(ev1a->sync_handle);
|
||||
iso_pi(sk)->bc_sid = ev1a->sid;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT);
|
||||
if (ev2) {
|
||||
/* Check if BIGInfo report has already been handled */
|
||||
|
|
|
|||
|
|
@ -852,6 +852,12 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
|||
if (ll_privacy_capable(hdev))
|
||||
settings |= MGMT_SETTING_LL_PRIVACY;
|
||||
|
||||
if (past_sender_capable(hdev))
|
||||
settings |= MGMT_SETTING_PAST_SENDER;
|
||||
|
||||
if (past_receiver_capable(hdev))
|
||||
settings |= MGMT_SETTING_PAST_RECEIVER;
|
||||
|
||||
settings |= MGMT_SETTING_PHY_CONFIGURATION;
|
||||
|
||||
return settings;
|
||||
|
|
@ -937,6 +943,12 @@ static u32 get_current_settings(struct hci_dev *hdev)
|
|||
if (ll_privacy_enabled(hdev))
|
||||
settings |= MGMT_SETTING_LL_PRIVACY;
|
||||
|
||||
if (past_sender_enabled(hdev))
|
||||
settings |= MGMT_SETTING_PAST_SENDER;
|
||||
|
||||
if (past_receiver_enabled(hdev))
|
||||
settings |= MGMT_SETTING_PAST_RECEIVER;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue