]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Bluetooth: Add support for LE ping feature
authorSpoorthi Ravishankar Koppad <spoorthix.k@intel.com>
Fri, 21 Jun 2019 09:21:56 +0000 (14:51 +0530)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 6 Jul 2019 13:29:12 +0000 (15:29 +0200)
Changes made to add HCI Write Authenticated Payload timeout
command for LE Ping feature.

As per the Core Specification 5.0 Volume 2 Part E Section 7.3.94,
the following code changes implements
HCI Write Authenticated Payload timeout command for LE Ping feature.

Signed-off-by: Spoorthi Ravishankar Koppad <spoorthix.k@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_debugfs.c
net/bluetooth/hci_event.c

index 9a5330eed7944fca7a7b013edf1d5d99c4d93128..5bc1e30dedde5b18df908abfbfdb15c705c99ab0 100644 (file)
@@ -1143,6 +1143,26 @@ struct hci_cp_write_sc_support {
        __u8    support;
 } __packed;
 
+#define HCI_OP_READ_AUTH_PAYLOAD_TO    0x0c7b
+struct hci_cp_read_auth_payload_to {
+       __le16  handle;
+} __packed;
+struct hci_rp_read_auth_payload_to {
+       __u8    status;
+       __le16  handle;
+       __le16  timeout;
+} __packed;
+
+#define HCI_OP_WRITE_AUTH_PAYLOAD_TO    0x0c7c
+struct hci_cp_write_auth_payload_to {
+       __le16  handle;
+       __le16  timeout;
+} __packed;
+struct hci_rp_write_auth_payload_to {
+       __u8    status;
+       __le16  handle;
+} __packed;
+
 #define HCI_OP_READ_LOCAL_OOB_EXT_DATA 0x0c7d
 struct hci_rp_read_local_oob_ext_data {
        __u8     status;
index 05b1b96f4d9e43bd97c2c5a3dd09a697c6dd2a92..ded574b32c2089c2140397a30d985ff7c1c550f0 100644 (file)
@@ -199,6 +199,8 @@ struct adv_info {
 /* Default min/max age of connection information (1s/3s) */
 #define DEFAULT_CONN_INFO_MIN_AGE      1000
 #define DEFAULT_CONN_INFO_MAX_AGE      3000
+/* Default authenticated payload timeout 30s */
+#define DEFAULT_AUTH_PAYLOAD_TIMEOUT   0x0bb8
 
 struct amp_assoc {
        __u16   len;
@@ -275,6 +277,7 @@ struct hci_dev {
        __u16           discov_interleaved_timeout;
        __u16           conn_info_min_age;
        __u16           conn_info_max_age;
+       __u16           auth_payload_timeout;
        __u8            ssp_debug_mode;
        __u8            hw_error_code;
        __u32           clock;
@@ -481,6 +484,7 @@ struct hci_conn {
        __u16           disc_timeout;
        __u16           conn_timeout;
        __u16           setting;
+       __u16           auth_payload_timeout;
        __u16           le_conn_min_interval;
        __u16           le_conn_max_interval;
        __u16           le_conn_interval;
index 15d1cb5aee18dab89a2f6f90bd01b2565807bcbb..17e5111daa116aedf7b616ae03bbb7a20e0c0719 100644 (file)
@@ -520,6 +520,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
        set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 
+       /* Set Default Authenticated payload timeout to 30s */
+       conn->auth_payload_timeout = DEFAULT_AUTH_PAYLOAD_TIMEOUT;
+
        if (conn->role == HCI_ROLE_MASTER)
                conn->out = true;
 
index b81bf53c5ac4a564491e71fcbdec4474903eaed5..ff9a755f4df35c73df26c90bd2b2f471af03c5dd 100644 (file)
@@ -3200,6 +3200,7 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
        hdev->conn_info_min_age = DEFAULT_CONN_INFO_MIN_AGE;
        hdev->conn_info_max_age = DEFAULT_CONN_INFO_MAX_AGE;
+       hdev->auth_payload_timeout = DEFAULT_AUTH_PAYLOAD_TIMEOUT;
 
        mutex_init(&hdev->lock);
        mutex_init(&hdev->req_lock);
index 51f5b1efc3a5c457f0e143c11a2e508f66d7e0a9..bb67f4a5479a2c79d724956c883d80e2a0c93345 100644 (file)
@@ -941,6 +941,35 @@ static int adv_max_interval_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get,
                        adv_max_interval_set, "%llu\n");
 
+static int auth_payload_timeout_set(void *data, u64 val)
+{
+       struct hci_dev *hdev = data;
+
+       if (val < 0x0001 || val > 0xffff)
+               return -EINVAL;
+
+       hci_dev_lock(hdev);
+       hdev->auth_payload_timeout = val;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int auth_payload_timeout_get(void *data, u64 *val)
+{
+       struct hci_dev *hdev = data;
+
+       hci_dev_lock(hdev);
+       *val = hdev->auth_payload_timeout;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(auth_payload_timeout_fops,
+                       auth_payload_timeout_get,
+                       auth_payload_timeout_set, "%llu\n");
+
 DEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter,
                       HCI_QUIRK_STRICT_DUPLICATE_FILTER);
 DEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery,
@@ -994,6 +1023,8 @@ void hci_debugfs_create_le(struct hci_dev *hdev)
                            &adv_max_interval_fops);
        debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs,
                           &hdev->discov_interleaved_timeout);
+       debugfs_create_file("auth_payload_timeout", 0644, hdev->debugfs, hdev,
+                           &auth_payload_timeout_fops);
 
        debugfs_create_file("quirk_strict_duplicate_filter", 0644,
                            hdev->debugfs, hdev,
index 9e4fcf406d9cd773e02b62998eb1cf387e3e622d..c1d3a303d97fbda890e546755535199af0420d2e 100644 (file)
@@ -579,6 +579,51 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
                memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
 }
 
+static void hci_cc_read_auth_payload_timeout(struct hci_dev *hdev,
+                                            struct sk_buff *skb)
+{
+       struct hci_rp_read_auth_payload_to *rp = (void *)skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn)
+               conn->auth_payload_timeout = __le16_to_cpu(rp->timeout);
+
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cc_write_auth_payload_timeout(struct hci_dev *hdev,
+                                             struct sk_buff *skb)
+{
+       struct hci_rp_write_auth_payload_to *rp = (void *)skb->data;
+       struct hci_conn *conn;
+       void *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO);
+       if (!sent)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn)
+               conn->auth_payload_timeout = get_unaligned_le16(sent + 2);
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_read_local_features(struct hci_dev *hdev,
                                       struct sk_buff *skb)
 {
@@ -2975,6 +3020,25 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
                goto unlock;
        }
 
+       /* Set the default Authenticated Payload Timeout after
+        * an LE Link is established. As per Core Spec v5.0, Vol 2, Part B
+        * Section 3.3, the HCI command WRITE_AUTH_PAYLOAD_TIMEOUT should be
+        * sent when the link is active and Encryption is enabled, the conn
+        * type can be either LE or ACL and controller must support LMP Ping.
+        * Ensure for AES-CCM encryption as well.
+        */
+       if (test_bit(HCI_CONN_ENCRYPT, &conn->flags) &&
+           test_bit(HCI_CONN_AES_CCM, &conn->flags) &&
+           ((conn->type == ACL_LINK && lmp_ping_capable(hdev)) ||
+            (conn->type == LE_LINK && (hdev->le_features[0] & HCI_LE_PING)))) {
+               struct hci_cp_write_auth_payload_to cp;
+
+               cp.handle = cpu_to_le16(conn->handle);
+               cp.timeout = cpu_to_le16(hdev->auth_payload_timeout);
+               hci_send_cmd(conn->hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO,
+                            sizeof(cp), &cp);
+       }
+
 notify:
        if (conn->state == BT_CONFIG) {
                if (!ev->status)
@@ -3170,6 +3234,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_write_sc_support(hdev, skb);
                break;
 
+       case HCI_OP_READ_AUTH_PAYLOAD_TO:
+               hci_cc_read_auth_payload_timeout(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_AUTH_PAYLOAD_TO:
+               hci_cc_write_auth_payload_timeout(hdev, skb);
+               break;
+
        case HCI_OP_READ_LOCAL_VERSION:
                hci_cc_read_local_version(hdev, skb);
                break;