Skip to content

Commit

Permalink
Bluetooth: Add support for LE ping feature
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Spoorthi Ravishankar Koppad authored and Marcel Holtmann committed Jul 6, 2019
1 parent 28261da commit 302975c
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 0 deletions.
20 changes: 20 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 31 additions & 0 deletions net/bluetooth/hci_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
72 changes: 72 additions & 0 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 302975c

Please sign in to comment.