From: SpoorthiX <spoorthix.k@xxxxxxxxx> 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: SpoorthiX <spoorthix.k@xxxxxxxxx> --- include/net/bluetooth/hci.h | 6 +++ include/net/bluetooth/mgmt.h | 9 +++++ net/bluetooth/hci_event.c | 28 ++++++++++++++ net/bluetooth/mgmt.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c36dc1e..c2a8080 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1130,6 +1130,12 @@ struct hci_cp_write_sc_support { __u8 support; } __packed; +#define HCI_OP_WRITE_AUTH_PAYLOAD_TO 0x0c7c +struct hci_cp_write_auth_payload_to { + __u16 conn_handle; + __u16 timeout; +} __packed; + #define HCI_OP_READ_LOCAL_OOB_EXT_DATA 0x0c7d struct hci_rp_read_local_oob_ext_data { __u8 status; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 9cee7dd..22c3052 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -654,6 +654,15 @@ struct mgmt_cp_set_phy_confguration { } __packed; #define MGMT_SET_PHY_CONFIGURATION_SIZE 4 + +#define MGMT_OP_WRITE_AUTH_PAYLOAD_TO 0x0046 +struct mgmt_cp_write_auth_payload_to { + __le16 conn_handle; + __le16 auth_to; +} __packed; +#define MGMT_OP_WRITE_AUTH_PAYLOAD_TO_SIZE 4 + + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ef9928d..eef7025 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1183,6 +1183,29 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } + +static void hci_cc_write_auth_payload_to (struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + struct hci_cp_write_auth_payload_to *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn->handle = cp->conn_handle; + + hci_dev_unlock(hdev); +} + static void hci_cc_le_set_ext_scan_param(struct hci_dev *hdev, struct sk_buff *skb) { @@ -5913,6 +5936,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_remote_oob_data_request_evt(hdev, skb); break; + #if IS_ENABLED(CONFIG_BT_HS) case HCI_EV_CHANNEL_SELECTED: hci_chan_selected_evt(hdev, skb); @@ -5939,6 +5963,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_num_comp_blocks_evt(hdev, skb); break; + case HCI_OP_WRITE_AUTH_PAYLOAD_TO: + hci_cc_write_auth_payload_to(hdev, skb); + break; + default: BT_DBG("%s event 0x%2.2x", hdev->name, event); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ccce954..ae6480e9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -106,6 +106,7 @@ MGMT_OP_START_LIMITED_DISCOVERY, MGMT_OP_READ_EXT_INFO, MGMT_OP_SET_APPEARANCE, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, }; static const u16 mgmt_events[] = { @@ -3595,6 +3596,96 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, mgmt_pending_remove(cmd); } +static void write_auth_payload_to_complete(struct hci_dev *hdev, u8 status, + u16 opcode, struct sk_buff *skb) +{ + struct mgmt_cp_write_auth_payload_to *cp; + struct mgmt_pending_cmd *cmd; + BT_DBG(""); + BT_INFO("status 0x%02x\n", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_WRITE_AUTH_PAYLOAD_TO, hdev); + if (!cmd) + goto unlock; + cp = cmd->param; + + if (status) { + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, + mgmt_status(status)); + } else { + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, 0, + NULL, 0); + } + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + + +static int write_auth_payload_to(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_write_auth_payload_to *cp = data; + struct hci_cp_write_auth_payload_to cp_payload; + struct mgmt_pending_cmd *cmd; + struct hci_request req; + u16 handle; + u16 timeout; + int err; + + hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, + MGMT_STATUS_REJECTED); + goto unlock; + } + + if (pending_find(MGMT_OP_WRITE_AUTH_PAYLOAD_TO, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, + MGMT_STATUS_BUSY); + goto unlock; + } + + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_WRITE_AUTH_PAYLOAD_TO, + 0, NULL, 0); + + cmd = mgmt_pending_add(sk, MGMT_OP_WRITE_AUTH_PAYLOAD_TO, hdev, data, + len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + hci_req_init(&req, hdev); + + handle = cp->conn_handle; + timeout = cp->auth_to; + + memset(&cp_payload, 0, sizeof(cp_payload)); + + cp_payload.conn_handle = handle; + cp_payload.timeout = timeout; + + hci_req_add(&req, HCI_OP_WRITE_AUTH_PAYLOAD_TO, sizeof(cp_payload), &cp_payload); + + err = hci_req_run_skb(&req, write_auth_payload_to_complete); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + return err; +} + + static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { @@ -6921,6 +7012,7 @@ static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev, { set_appearance, MGMT_SET_APPEARANCE_SIZE }, { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE }, { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE }, + { write_auth_payload_to, MGMT_OP_WRITE_AUTH_PAYLOAD_TO_SIZE }, }; void mgmt_index_added(struct hci_dev *hdev) -- 1.9.1