2021-04-19 20:19:35

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 00/10] Bluetooth: HCI: Use skb_pull to parse events

From: Luiz Augusto von Dentz <[email protected]>

This set ensures events received have the minimum required length using
skb_pull to advance on packet, it also rework some of events to take
advantage flex_array_size for events that can have variable size.

This should fix issues found by szybot like:

[syzbot] KMSAN: uninit-value in hci_event_packet

v2: Fixes issues found by CI

Luiz Augusto von Dentz (10):
Bluetooth: HCI: Use skb_pull to parse BR/EDR events
Bluetooth: HCI: Use skb_pull to parse Command Complete event
Bluetooth: HCI: Use skb_pull to parse Number of Complete Packets event
Bluetooth: HCI: Use skb_pull to parse Inquiry Result event
Bluetooth: HCI: Use skb_pull to parse Inquiry Result with RSSI event
Bluetooth: HCI: Use skb_pull to parse Extended Inquiry Result event
Bluetooth: HCI: Use skb_pull to parse LE Metaevents
Bluetooth: HCI: Use skb_pull to parse LE Advertising Report event
Bluetooth: HCI: Use skb_pull to parse LE Extended Advertising Report
event
Bluetooth: HCI: Use skb_pull to parse LE Direct Advertising Report
event

include/net/bluetooth/hci.h | 59 +-
net/bluetooth/hci_event.c | 1311 +++++++++++++++++++++++++++--------
2 files changed, 1051 insertions(+), 319 deletions(-)

--
2.30.2


2021-04-19 20:20:37

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the BR/EDR events received have the minimum
required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 4 +
net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
2 files changed, 229 insertions(+), 47 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ea4ae551c426..f1f505355e81 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
} __packed;

/* ---- HCI Events ---- */
+struct hci_ev_status {
+ __u8 status;
+} __packed;
+
#define HCI_EV_INQUIRY_COMPLETE 0x01

#define HCI_EV_INQUIRY_RESULT 0x02
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5e99968939ce..077541fcba41 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -42,6 +42,30 @@

/* Handle HCI Event packets */

+static void *hci_skb_pull(struct sk_buff *skb, size_t len)
+{
+ void *data = skb->data;
+
+ if (skb->len < len)
+ return NULL;
+
+ skb_pull(skb, len);
+
+ return data;
+}
+
+static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+ u8 ev, size_t len)
+{
+ void *data;
+
+ data = hci_skb_pull(skb, len);
+ if (!data)
+ bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
+
+ return data;
+}
+
static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
u8 *new_status)
{
@@ -2507,11 +2531,15 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)

static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *ev;
struct discovery_state *discov = &hdev->discovery;
struct inquiry_entry *e;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_conn_check_pending(hdev);

@@ -2604,9 +2632,13 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_conn_complete *ev = (void *) skb->data;
+ struct hci_ev_conn_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CONN_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -2728,12 +2760,16 @@ static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr)

static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_conn_request *ev = (void *) skb->data;
+ struct hci_ev_conn_request *ev;
int mask = hdev->link_mode;
struct inquiry_entry *ie;
struct hci_conn *conn;
__u8 flags = 0;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CONN_REQUEST, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
ev->link_type);

@@ -2839,13 +2875,17 @@ static u8 hci_to_mgmt_reason(u8 err)

static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_disconn_complete *ev = (void *) skb->data;
+ struct hci_ev_disconn_complete *ev;
u8 reason;
struct hci_conn_params *params;
struct hci_conn *conn;
bool mgmt_connected;
u8 type;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_DISCONN_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -2931,9 +2971,13 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_auth_complete *ev = (void *) skb->data;
+ struct hci_ev_auth_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_AUTH_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3001,9 +3045,13 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_remote_name *ev = (void *) skb->data;
+ struct hci_ev_remote_name *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_REMOTE_NAME, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_conn_check_pending(hdev);
@@ -3084,9 +3132,13 @@ static void read_enc_key_size_complete(struct hci_dev *hdev, u8 status,

static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_encrypt_change *ev = (void *) skb->data;
+ struct hci_ev_encrypt_change *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_ENCRYPT_CHANGE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3199,9 +3251,14 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
+ struct hci_ev_change_link_key_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CHANGE_LINK_KEY_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3222,9 +3279,13 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
static void hci_remote_features_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_remote_features *ev = (void *) skb->data;
+ struct hci_ev_remote_features *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_REMOTE_FEATURES, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3654,9 +3715,11 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb)
{
- struct hci_ev_cmd_status *ev = (void *) skb->data;
+ struct hci_ev_cmd_status *ev;

- skb_pull(skb, sizeof(*ev));
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CMD_STATUS, sizeof(*ev));
+ if (!ev)
+ return;

*opcode = __le16_to_cpu(ev->opcode);
*status = ev->status;
@@ -3764,7 +3827,11 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,

static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_hardware_error *ev = (void *) skb->data;
+ struct hci_ev_hardware_error *ev;
+
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_HARDWARE_ERROR, sizeof(*ev));
+ if (!ev)
+ return;

hdev->hw_error_code = ev->code;

@@ -3773,9 +3840,13 @@ static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_role_change *ev = (void *) skb->data;
+ struct hci_ev_role_change *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_ROLE_CHANGE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3883,17 +3954,19 @@ static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,

static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
+ struct hci_ev_num_comp_blocks *ev;
int i;

- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
- bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS, sizeof(*ev));
+ if (!ev)
return;
- }

- if (skb->len < sizeof(*ev) ||
- skb->len < struct_size(ev, handles, ev->num_hndl)) {
- BT_DBG("%s bad parameters", hdev->name);
+ if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS,
+ flex_array_size(ev, handles, ev->num_hndl)))
+ return;
+
+ if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
+ bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
return;
}

@@ -3934,9 +4007,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_mode_change *ev = (void *) skb->data;
+ struct hci_ev_mode_change *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_MODE_CHANGE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -3962,9 +4039,13 @@ static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_pin_code_req *ev = (void *) skb->data;
+ struct hci_ev_pin_code_req *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_PIN_CODE_REQ, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4032,11 +4113,15 @@ static void conn_set_key(struct hci_conn *conn, u8 key_type, u8 pin_len)

static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_link_key_req *ev = (void *) skb->data;
+ struct hci_ev_link_key_req *ev;
struct hci_cp_link_key_reply cp;
struct hci_conn *conn;
struct link_key *key;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_LINK_KEY_REQ, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

if (!hci_dev_test_flag(hdev, HCI_MGMT))
@@ -4092,12 +4177,16 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_link_key_notify *ev = (void *) skb->data;
+ struct hci_ev_link_key_notify *ev;
struct hci_conn *conn;
struct link_key *key;
bool persistent;
u8 pin_len = 0;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_LINK_KEY_NOTIFY, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4152,9 +4241,13 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_clock_offset *ev = (void *) skb->data;
+ struct hci_ev_clock_offset *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CLOCK_OFFSET, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -4175,9 +4268,13 @@ static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_pkt_type_change *ev = (void *) skb->data;
+ struct hci_ev_pkt_type_change *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_PKT_TYPE_CHANGE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -4191,9 +4288,13 @@ static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
+ struct hci_ev_pscan_rep_mode *ev;
struct inquiry_entry *ie;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_PSCAN_REP_MODE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4281,9 +4382,14 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
static void hci_remote_ext_features_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_remote_ext_features *ev = (void *) skb->data;
+ struct hci_ev_remote_ext_features *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_REMOTE_EXT_FEATURES,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4345,9 +4451,13 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
+ struct hci_ev_sync_conn_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_SYNC_CONN_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -4493,9 +4603,14 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_key_refresh_complete *ev = (void *) skb->data;
+ struct hci_ev_key_refresh_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_KEY_REFRESH_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x handle 0x%4.4x", hdev->name, ev->status,
__le16_to_cpu(ev->handle));

@@ -4602,9 +4717,13 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)

static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_io_capa_request *ev = (void *) skb->data;
+ struct hci_ev_io_capa_request *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_IO_CAPA_REQUEST, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4671,9 +4790,13 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_io_capa_reply *ev = (void *) skb->data;
+ struct hci_ev_io_capa_reply *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_IO_CAPA_REPLY, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4692,10 +4815,15 @@ static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_user_confirm_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_user_confirm_req *ev = (void *) skb->data;
+ struct hci_ev_user_confirm_req *ev;
int loc_mitm, rem_mitm, confirm_hint = 0;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_USER_CONFIRM_REQUEST,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4777,7 +4905,12 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
static void hci_user_passkey_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_user_passkey_req *ev = (void *) skb->data;
+ struct hci_ev_user_passkey_req *ev;
+
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_USER_PASSKEY_REQUEST,
+ sizeof(*ev));
+ if (!ev)
+ return;

BT_DBG("%s", hdev->name);

@@ -4788,9 +4921,14 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+ struct hci_ev_user_passkey_notify *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_USER_PASSKEY_NOTIFY,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4808,9 +4946,13 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev,

static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_keypress_notify *ev = (void *) skb->data;
+ struct hci_ev_keypress_notify *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_KEYPRESS_NOTIFY, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4847,9 +4989,14 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
+ struct hci_ev_simple_pair_complete *ev;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_SIMPLE_PAIR_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4878,10 +5025,15 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
static void hci_remote_host_features_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_remote_host_features *ev = (void *) skb->data;
+ struct hci_ev_remote_host_features *ev;
struct inquiry_entry *ie;
struct hci_conn *conn;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_REMOTE_HOST_FEATURES,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4900,9 +5052,14 @@ static void hci_remote_host_features_evt(struct hci_dev *hdev,
static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+ struct hci_ev_remote_oob_data_request *ev;
struct oob_data *data;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_REMOTE_OOB_DATA_REQUEST,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s", hdev->name);

hci_dev_lock(hdev);
@@ -4954,12 +5111,14 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
#if IS_ENABLED(CONFIG_BT_HS)
static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_channel_selected *ev = (void *)skb->data;
+ struct hci_ev_channel_selected *ev;
struct hci_conn *hcon;

- BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CHANNEL_SELECTED, sizeof(*ev));
+ if (!ev)
+ return;

- skb_pull(skb, sizeof(*ev));
+ BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);

hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
@@ -4971,9 +5130,13 @@ static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_phy_link_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_phy_link_complete *ev = (void *) skb->data;
+ struct hci_ev_phy_link_complete *ev;
struct hci_conn *hcon, *bredr_hcon;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_PHY_LINK_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
ev->status);

@@ -5011,11 +5174,16 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,

static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_logical_link_complete *ev = (void *) skb->data;
+ struct hci_ev_logical_link_complete *ev;
struct hci_conn *hcon;
struct hci_chan *hchan;
struct amp_mgr *mgr;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_LOGICAL_LINK_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
hdev->name, le16_to_cpu(ev->handle), ev->phy_handle,
ev->status);
@@ -5051,9 +5219,14 @@ static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data;
+ struct hci_ev_disconn_logical_link_complete *ev;
struct hci_chan *hchan;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name,
le16_to_cpu(ev->handle), ev->status);

@@ -5075,9 +5248,14 @@ static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data;
+ struct hci_ev_disconn_phy_link_complete *ev;
struct hci_conn *hcon;

+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_DISCONN_PHY_LINK_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

if (ev->status)
--
2.30.2

2021-04-19 20:20:50

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 04/10] Bluetooth: HCI: Use skb_pull to parse Inquiry Result event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the Inquiry Result events received have
the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 5 +++++
net/bluetooth/hci_event.c | 19 ++++++++++++++-----
2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 9251ae3a2ce0..b65205b4d830 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1910,6 +1910,11 @@ struct inquiry_info {
__le16 clock_offset;
} __packed;

+struct hci_ev_inquiry_result {
+ __u8 num;
+ struct inquiry_info info[];
+};
+
#define HCI_EV_CONN_COMPLETE 0x03
struct hci_ev_conn_complete {
__u8 status;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c353dfafb04c..6516538fe238 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2990,13 +2990,21 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
+ struct hci_ev_inquiry_result *ev;
struct inquiry_data data;
- struct inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
+ int i;

- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_RESULT, sizeof(*ev));
+ if (!ev)
+ return;

- if (!num_rsp || skb->len < num_rsp * sizeof(*info) + 1)
+ if (!hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_RESULT,
+ flex_array_size(ev, info, ev->num)))
+ return;
+
+ BT_DBG("%s num %d", hdev->name, ev->num);
+
+ if (!ev->num)
return;

if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
@@ -3004,7 +3012,8 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- for (; num_rsp; num_rsp--, info++) {
+ for (i = 0; i < ev->num; i++) {
+ struct inquiry_info *info = &ev->info[i];
u32 flags;

bacpy(&data.bdaddr, &info->bdaddr);
--
2.30.2

2021-04-19 20:21:05

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 03/10] Bluetooth: HCI: Use skb_pull to parse Number of Complete Packets event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the Number of Complete Packets events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 2 +-
net/bluetooth/hci_event.c | 20 +++++++++++---------
2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index f1f505355e81..9251ae3a2ce0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2021,7 +2021,7 @@ struct hci_comp_pkts_info {
} __packed;

struct hci_ev_num_comp_pkts {
- __u8 num_hndl;
+ __u8 num;
struct hci_comp_pkts_info handles[];
} __packed;

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cc2d68389edc..c353dfafb04c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4264,23 +4264,25 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
+ struct hci_ev_num_comp_pkts *ev;
int i;

- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
- bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_PKTS, sizeof(*ev));
+ if (!ev)
return;
- }

- if (skb->len < sizeof(*ev) ||
- skb->len < struct_size(ev, handles, ev->num_hndl)) {
- BT_DBG("%s bad parameters", hdev->name);
+ if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_PKTS,
+ flex_array_size(ev, handles, ev->num)))
+ return;
+
+ if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
+ bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
return;
}

- BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+ BT_DBG("%s num %d", hdev->name, ev->num);

- for (i = 0; i < ev->num_hndl; i++) {
+ for (i = 0; i < ev->num; i++) {
struct hci_comp_pkts_info *info = &ev->handles[i];
struct hci_conn *conn;
__u16 handle, count;
--
2.30.2

2021-04-19 20:21:15

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 06/10] Bluetooth: HCI: Use skb_pull to parse Extended Inquiry Result event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the Extended Inquiry Result events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 5 +++++
net/bluetooth/hci_event.c | 20 +++++++++++++++-----
2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 53e16ad79698..f416ad71fd2d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2155,6 +2155,11 @@ struct extended_inquiry_info {
__u8 data[240];
} __packed;

+struct hci_ev_ext_inquiry_result {
+ __u8 num;
+ struct extended_inquiry_info info[];
+} __packed;
+
#define HCI_EV_KEY_REFRESH_COMPLETE 0x30
struct hci_ev_key_refresh_complete {
__u8 status;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 05d680a5f9c3..9776c395412c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4968,14 +4968,23 @@ static inline size_t eir_get_length(u8 *eir, size_t eir_len)
static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
+ struct hci_ev_ext_inquiry_result *ev;
struct inquiry_data data;
- struct extended_inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
size_t eir_len;
+ int i;

- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_EXTENDED_INQUIRY_RESULT,
+ sizeof(*ev));
+ if (!ev)
+ return;

- if (!num_rsp || skb->len < num_rsp * sizeof(*info) + 1)
+ if (!hci_ev_skb_pull(hdev, skb, HCI_EV_EXTENDED_INQUIRY_RESULT,
+ flex_array_size(ev, info, ev->num)))
+ return;
+
+ BT_DBG("%s num %d", hdev->name, ev->num);
+
+ if (!ev->num)
return;

if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
@@ -4983,7 +4992,8 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,

hci_dev_lock(hdev);

- for (; num_rsp; num_rsp--, info++) {
+ for (i = 0; i < ev->num; i++) {
+ struct extended_inquiry_info *info = &ev->info[i];
u32 flags;
bool name_known;

--
2.30.2

2021-04-19 20:21:15

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 05/10] Bluetooth: HCI: Use skb_pull to parse Inquiry Result with RSSI event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the Inquiry Result with RSSI events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 12 +++++++++--
net/bluetooth/hci_event.c | 40 +++++++++++++++++++++----------------
2 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b65205b4d830..53e16ad79698 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2076,7 +2076,7 @@ struct hci_ev_pscan_rep_mode {
} __packed;

#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
-struct inquiry_info_with_rssi {
+struct inquiry_info_rssi {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
@@ -2084,7 +2084,7 @@ struct inquiry_info_with_rssi {
__le16 clock_offset;
__s8 rssi;
} __packed;
-struct inquiry_info_with_rssi_and_pscan_mode {
+struct inquiry_info_rssi_pscan {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
@@ -2093,6 +2093,14 @@ struct inquiry_info_with_rssi_and_pscan_mode {
__le16 clock_offset;
__s8 rssi;
} __packed;
+struct hci_ev_inquiry_result_rssi {
+ __u8 num;
+ struct inquiry_info_rssi info[];
+} __packed;
+struct hci_ev_inquiry_result_rssi_pscan {
+ __u8 num;
+ struct inquiry_info_rssi_pscan info[];
+} __packed;

#define HCI_EV_REMOTE_EXT_FEATURES 0x23
struct hci_ev_remote_ext_features {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6516538fe238..05d680a5f9c3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4720,12 +4720,21 @@ static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
+ union {
+ struct hci_ev_inquiry_result_rssi *res1;
+ struct hci_ev_inquiry_result_rssi_pscan *res2;
+ } *ev;
struct inquiry_data data;
- int num_rsp = *((__u8 *) skb->data);
+ int i;

- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_RESULT_WITH_RSSI,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
+ BT_DBG("%s num_rsp %d", hdev->name, ev->res1->num);

- if (!num_rsp)
+ if (!ev->res1->num)
return;

if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
@@ -4733,16 +4742,13 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,

hci_dev_lock(hdev);

- if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
- struct inquiry_info_with_rssi_and_pscan_mode *info;
- info = (void *) (skb->data + 1);
+ if (skb->len == flex_array_size(ev, res2->info, ev->res2->num)) {
+ struct inquiry_info_rssi_pscan *info;

- if (skb->len < num_rsp * sizeof(*info) + 1)
- goto unlock;
-
- for (; num_rsp; num_rsp--, info++) {
+ for (i = 0; i < ev->res2->num; i++) {
u32 flags;

+ info = &ev->res2->info[i];
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
@@ -4758,15 +4764,13 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
info->dev_class, info->rssi,
flags, NULL, 0, NULL, 0);
}
- } else {
- struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
+ } else if (skb->len == flex_array_size(ev, res1->info, ev->res1->num)) {
+ struct inquiry_info_rssi *info;

- if (skb->len < num_rsp * sizeof(*info) + 1)
- goto unlock;
-
- for (; num_rsp; num_rsp--, info++) {
+ for (i = 0; i < ev->res1->num; i++) {
u32 flags;

+ info = &ev->res1->info[i];
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
@@ -4782,9 +4786,11 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
info->dev_class, info->rssi,
flags, NULL, 0, NULL, 0);
}
+ } else {
+ bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x",
+ HCI_EV_INQUIRY_RESULT_WITH_RSSI);
}

-unlock:
hci_dev_unlock(hdev);
}

--
2.30.2

2021-04-19 20:21:18

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 02/10] Bluetooth: HCI: Use skb_pull to parse Command Complete event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the Command Complete events received have
the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
net/bluetooth/hci_event.c | 766 +++++++++++++++++++++++++++++---------
1 file changed, 581 insertions(+), 185 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 077541fcba41..cc2d68389edc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -66,12 +66,28 @@ static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
return data;
}

+static void *hci_cc_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+ u16 op, size_t len)
+{
+ void *data;
+
+ data = hci_skb_pull(skb, len);
+ if (!data)
+ bt_dev_err(hdev, "Malformed Command Complete: 0x%4.4x", op);
+
+ return data;
+}
+
static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
u8 *new_status)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_INQUIRY_CANCEL, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

/* It is possible that we receive Inquiry Complete event right
* before we receive Inquiry Cancel Command Complete event, in
@@ -80,14 +96,14 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
* we actually achieve what Inquiry Cancel wants to achieve,
* which is to end the last Inquiry session.
*/
- if (status == 0x0c && !test_bit(HCI_INQUIRY, &hdev->flags)) {
+ if (rp->status == 0x0c && !test_bit(HCI_INQUIRY, &hdev->flags)) {
bt_dev_warn(hdev, "Ignoring error of Inquiry Cancel command");
- status = 0x00;
+ rp->status = 0x00;
}

- *new_status = status;
+ *new_status = rp->status;

- if (status)
+ if (rp->status)
return;

clear_bit(HCI_INQUIRY, &hdev->flags);
@@ -108,11 +124,15 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,

static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PERIODIC_INQ, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

hci_dev_set_flag(hdev, HCI_PERIODIC_INQ);
@@ -120,11 +140,15 @@ static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_EXIT_PERIODIC_INQ, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ);
@@ -140,9 +164,13 @@ static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,

static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_role_discovery *rp = (void *) skb->data;
+ struct hci_rp_role_discovery *rp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_ROLE_DISCOVERY, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -159,9 +187,13 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_link_policy *rp = (void *) skb->data;
+ struct hci_rp_read_link_policy *rp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LINK_POLICY, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -178,10 +210,14 @@ static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_write_link_policy *rp = (void *) skb->data;
+ struct hci_rp_write_link_policy *rp;
struct hci_conn *conn;
void *sent;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LINK_POLICY, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -203,7 +239,12 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
+ struct hci_rp_read_def_link_policy *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DEF_LINK_POLICY,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -216,12 +257,17 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_DEF_LINK_POLICY,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
@@ -233,13 +279,17 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev,

static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_RESET, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

clear_bit(HCI_RESET, &hdev->flags);

- if (status)
+ if (rp->status)
return;

/* Reset all non-persistent flags */
@@ -267,9 +317,14 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_stored_link_key *rp = (void *)skb->data;
+ struct hci_rp_read_stored_link_key *rp;
struct hci_cp_read_stored_link_key *sent;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_STORED_LINK_KEY,
+ sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_READ_STORED_LINK_KEY);
@@ -285,7 +340,12 @@ static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_delete_stored_link_key *rp = (void *)skb->data;
+ struct hci_rp_delete_stored_link_key *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_DELETE_STORED_LINK_KEY,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -300,10 +360,14 @@ static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,

static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LOCAL_NAME, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
if (!sent)
@@ -312,8 +376,8 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock(hdev);

if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_set_local_name_complete(hdev, sent, status);
- else if (!status)
+ mgmt_set_local_name_complete(hdev, sent, rp->status);
+ else if (!rp->status)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);

hci_dev_unlock(hdev);
@@ -321,7 +385,11 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_local_name *rp = (void *) skb->data;
+ struct hci_rp_read_local_name *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_NAME, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -335,10 +403,14 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_AUTH_ENABLE, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
if (!sent)
@@ -346,7 +418,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- if (!status) {
+ if (!rp->status) {
__u8 param = *((__u8 *) sent);

if (param == AUTH_ENABLED)
@@ -356,20 +428,24 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
}

if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_auth_enable_complete(hdev, status);
+ mgmt_auth_enable_complete(hdev, rp->status);

hci_dev_unlock(hdev);
}

static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
__u8 param;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_ENCRYPT_MODE, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
@@ -386,11 +462,15 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
__u8 param;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SCAN_ENABLE, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
if (!sent)
@@ -400,7 +480,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- if (status) {
+ if (rp->status) {
hdev->discov_timeout = 0;
goto done;
}
@@ -421,13 +501,17 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *)skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_set_event_filter *cp;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SCAN_ENABLE, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_SET_EVENT_FLT);
@@ -444,7 +528,11 @@ static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
+ struct hci_rp_read_class_of_dev *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLASS_OF_DEV, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -459,10 +547,14 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLASS_OF_DEV, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
if (!sent)
@@ -470,20 +562,24 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- if (status == 0)
+ if (!rp->status)
memcpy(hdev->dev_class, sent, 3);

if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_set_class_of_dev_complete(hdev, sent, status);
+ mgmt_set_class_of_dev_complete(hdev, sent, rp->status);

hci_dev_unlock(hdev);
}

static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_voice_setting *rp = (void *) skb->data;
+ struct hci_rp_read_voice_setting *rp;
__u16 setting;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_VOICE_SETTING, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -505,13 +601,18 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_write_voice_setting(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
__u16 setting;
void *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_VOICE_SETTING,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
@@ -534,7 +635,12 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_num_supported_iac *rp = (void *) skb->data;
+ struct hci_rp_read_num_supported_iac *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_NUM_SUPPORTED_IAC,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -548,10 +654,14 @@ static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,

static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_write_ssp_mode *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SSP_MODE, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
if (!sent)
@@ -559,7 +669,7 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- if (!status) {
+ if (!rp->status) {
if (sent->mode)
hdev->features[1][0] |= LMP_HOST_SSP;
else
@@ -567,8 +677,8 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
}

if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_ssp_enable_complete(hdev, sent->mode, status);
- else if (!status) {
+ mgmt_ssp_enable_complete(hdev, sent->mode, rp->status);
+ else if (!rp->status) {
if (sent->mode)
hci_dev_set_flag(hdev, HCI_SSP_ENABLED);
else
@@ -580,10 +690,14 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
{
- u8 status = *((u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_write_sc_support *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SC_SUPPORT, sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
if (!sent)
@@ -591,14 +705,14 @@ static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_lock(hdev);

- if (!status) {
+ if (!rp->status) {
if (sent->support)
hdev->features[1][0] |= LMP_HOST_SC;
else
hdev->features[1][0] &= ~LMP_HOST_SC;
}

- if (!hci_dev_test_flag(hdev, HCI_MGMT) && !status) {
+ if (!hci_dev_test_flag(hdev, HCI_MGMT) && !rp->status) {
if (sent->support)
hci_dev_set_flag(hdev, HCI_SC_ENABLED);
else
@@ -610,7 +724,11 @@ static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_local_version *rp = (void *) skb->data;
+ struct hci_rp_read_local_version *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_VERSION, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -630,7 +748,12 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_local_commands(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_commands *rp = (void *) skb->data;
+ struct hci_rp_read_local_commands *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_COMMANDS,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -645,9 +768,14 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
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_rp_read_auth_payload_to *rp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_AUTH_PAYLOAD_TO,
+ sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -665,10 +793,14 @@ static void hci_cc_read_auth_payload_timeout(struct hci_dev *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_rp_write_auth_payload_to *rp;
struct hci_conn *conn;
void *sent;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_AUTH_PAYLOAD_TO, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -690,7 +822,12 @@ static void hci_cc_write_auth_payload_timeout(struct hci_dev *hdev,
static void hci_cc_read_local_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_features *rp = (void *) skb->data;
+ struct hci_rp_read_local_features *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_FEATURES,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -740,7 +877,12 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
+ struct hci_rp_read_local_ext_features *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_EXT_FEATURES,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -757,7 +899,12 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
+ struct hci_rp_read_flow_control_mode *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_FLOW_CONTROL_MODE,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -769,7 +916,11 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,

static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_buffer_size *rp = (void *) skb->data;
+ struct hci_rp_read_buffer_size *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_BUFFER_SIZE, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -795,7 +946,11 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_bd_addr *rp = (void *) skb->data;
+ struct hci_rp_read_bd_addr *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_BD_ADDR, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -812,7 +967,12 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_local_pairing_opts(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_pairing_opts *rp = (void *) skb->data;
+ struct hci_rp_read_local_pairing_opts *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_PAIRING_OPTS,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -829,7 +989,12 @@ static void hci_cc_read_local_pairing_opts(struct hci_dev *hdev,
static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
+ struct hci_rp_read_page_scan_activity *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_ACTIVITY,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -845,12 +1010,17 @@ static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
struct sk_buff *skb)
{
- u8 status = *((u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_write_page_scan_activity *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_ACTIVITY,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
@@ -864,7 +1034,12 @@ static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
+ struct hci_rp_read_page_scan_type *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_PAGE_SCAN_TYPE,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -878,12 +1053,17 @@ static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
struct sk_buff *skb)
{
- u8 status = *((u8 *) skb->data);
+ struct hci_ev_status *rp;
u8 *type;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_PAGE_SCAN_TYPE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
@@ -894,7 +1074,11 @@ static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
static void hci_cc_read_data_block_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_data_block_size *rp = (void *) skb->data;
+ struct hci_rp_read_data_block_size *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DATA_BLOCK_SIZE, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -913,15 +1097,18 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,

static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_clock *rp = (void *) skb->data;
+ struct hci_rp_read_clock *rp;
struct hci_cp_read_clock *cp;
struct hci_conn *conn;

BT_DBG("%s", hdev->name);

- if (skb->len < sizeof(*rp))
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_CLOCK, sizeof(*rp));
+ if (!rp)
return;

+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
if (rp->status)
return;

@@ -949,7 +1136,11 @@ static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+ struct hci_rp_read_local_amp_info *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_AMP_INFO, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -971,7 +1162,11 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
+ struct hci_rp_read_inq_rsp_tx_power *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_INQ_RSP_TX_POWER, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -984,7 +1179,12 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
static void hci_cc_read_def_err_data_reporting(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_def_err_data_reporting *rp = (void *)skb->data;
+ struct hci_rp_read_def_err_data_reporting *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_DEF_ERR_DATA_REPORTING,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -997,12 +1197,17 @@ static void hci_cc_read_def_err_data_reporting(struct hci_dev *hdev,
static void hci_cc_write_def_err_data_reporting(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *)skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_write_def_err_data_reporting *cp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING);
@@ -1014,10 +1219,14 @@ static void hci_cc_write_def_err_data_reporting(struct hci_dev *hdev,

static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_pin_code_reply *rp = (void *) skb->data;
+ struct hci_rp_pin_code_reply *rp;
struct hci_cp_pin_code_reply *cp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PIN_CODE_REPLY, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

hci_dev_lock(hdev);
@@ -1042,7 +1251,11 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
+ struct hci_rp_pin_code_neg_reply *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1058,7 +1271,11 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
+ struct hci_rp_le_read_buffer_size *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_BUFFER_SIZE, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1076,7 +1293,11 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
static void hci_cc_le_read_local_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_local_features *rp = (void *) skb->data;
+ struct hci_rp_le_read_local_features *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_LOCAL_FEATURES, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1089,7 +1310,11 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
+ struct hci_rp_le_read_adv_tx_power *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_ADV_TX_POWER, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1101,7 +1326,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,

static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+ struct hci_rp_user_confirm_reply *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_CONFIRM_REPLY, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1117,7 +1346,11 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+ struct hci_rp_user_confirm_reply *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1132,7 +1365,11 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,

static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+ struct hci_rp_user_confirm_reply *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_PASSKEY_REPLY, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1148,7 +1385,11 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+ struct hci_rp_user_confirm_reply *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_USER_PASSKEY_NEG_REPLY, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1164,7 +1405,11 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+ struct hci_rp_read_local_oob_data *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_OOB_DATA, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
}
@@ -1172,19 +1417,27 @@ static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
+ struct hci_rp_read_local_oob_ext_data *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_LOCAL_OOB_EXT_DATA, sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
}

static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
bdaddr_t *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_RANDOM_ADDR, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
@@ -1200,12 +1453,16 @@ static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_le_set_default_phy *cp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_DEFAULT_PHY);
@@ -1223,11 +1480,18 @@ static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_le_set_adv_set_rand_addr *cp;
struct adv_info *adv_instance;

- if (status)
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
+ sizeof(*rp));
+ if (!rp)
+ return;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_SET_RAND_ADDR);
@@ -1251,7 +1515,12 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
static void hci_cc_le_read_transmit_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_transmit_power *rp = (void *)skb->data;
+ struct hci_rp_le_read_transmit_power *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_TRANSMIT_POWER,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1264,11 +1533,16 @@ static void hci_cc_le_read_transmit_power(struct hci_dev *hdev,

static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
- __u8 *sent, status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
+ __u8 *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_ENABLE, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
@@ -1301,11 +1575,16 @@ static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_set_ext_adv_enable *cp;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_ADV_ENABLE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE);
@@ -1334,11 +1613,15 @@ static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_cp_le_set_scan_param *cp;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_SCAN_PARAM, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
@@ -1356,12 +1639,17 @@ static void hci_cc_le_set_ext_scan_param(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_set_ext_scan_params *cp;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
struct hci_cp_le_scan_phy_params *phy_param;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS);
@@ -1470,11 +1758,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_set_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_SCAN_ENABLE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
@@ -1488,11 +1781,16 @@ static void hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_set_ext_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE);
@@ -1505,7 +1803,12 @@ static void hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev,
static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_num_supported_adv_sets *rp = (void *) skb->data;
+ struct hci_rp_le_read_num_supported_adv_sets *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x No of Adv sets %u", hdev->name, rp->status,
rp->num_of_sets);
@@ -1519,7 +1822,12 @@ static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_white_list_size *rp = (void *) skb->data;
+ struct hci_rp_le_read_white_list_size *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_WHITE_LIST_SIZE,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);

@@ -1532,11 +1840,16 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_CLEAR_WHITE_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

hci_bdaddr_list_clear(&hdev->le_white_list);
@@ -1546,11 +1859,16 @@ static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_add_to_white_list *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_ADD_TO_WHITE_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
@@ -1565,11 +1883,16 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_del_from_white_list *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_DEL_FROM_WHITE_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
@@ -1583,7 +1906,12 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_supported_states *rp = (void *) skb->data;
+ struct hci_rp_le_read_supported_states *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_SUPPORTED_STATES,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1596,7 +1924,12 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
static void hci_cc_le_read_def_data_len(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_def_data_len *rp = (void *) skb->data;
+ struct hci_rp_le_read_def_data_len *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_DEF_DATA_LEN,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1611,11 +1944,16 @@ static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_write_def_data_len *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_WRITE_DEF_DATA_LEN,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN);
@@ -1630,11 +1968,16 @@ static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_add_to_resolv_list *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_ADD_TO_RESOLV_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST);
@@ -1650,11 +1993,16 @@ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_del_from_resolv_list *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_DEL_FROM_RESOLV_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST);
@@ -1668,11 +2016,16 @@ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_CLEAR_RESOLV_LIST,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

hci_bdaddr_list_clear(&hdev->le_resolv_list);
@@ -1681,7 +2034,12 @@ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_resolv_list_size *rp = (void *) skb->data;
+ struct hci_rp_le_read_resolv_list_size *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_RESOLV_LIST_SIZE,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);

@@ -1694,11 +2052,17 @@ static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 *sent, status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;
+ __u8 *sent;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE);
@@ -1718,7 +2082,12 @@ static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
static void hci_cc_le_read_max_data_len(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_rp_le_read_max_data_len *rp = (void *) skb->data;
+ struct hci_rp_le_read_max_data_len *rp;
+
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_READ_MAX_DATA_LEN,
+ sizeof(*rp));
+ if (!rp)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

@@ -1735,11 +2104,16 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_write_le_host_supported *sent;
- __u8 status = *((__u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
@@ -1768,11 +2142,15 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_cp_le_set_adv_param *cp;
- u8 status = *((u8 *) skb->data);
+ struct hci_ev_status *rp;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_ADV_PARAM, sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
@@ -1786,10 +2164,15 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_le_set_ext_adv_params *rp = (void *) skb->data;
+ struct hci_rp_le_set_ext_adv_params *rp;
struct hci_cp_le_set_ext_adv_params *cp;
struct adv_info *adv_instance;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_LE_SET_EXT_ADV_PARAMS,
+ sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -1817,9 +2200,13 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_rp_read_rssi *rp = (void *) skb->data;
+ struct hci_rp_read_rssi *rp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_RSSI, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -1837,9 +2224,13 @@ static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_cp_read_tx_power *sent;
- struct hci_rp_read_tx_power *rp = (void *) skb->data;
+ struct hci_rp_read_tx_power *rp;
struct hci_conn *conn;

+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_READ_TX_POWER, sizeof(*rp));
+ if (!rp)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (rp->status)
@@ -1870,12 +2261,17 @@ static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
- u8 status = *((u8 *) skb->data);
+ struct hci_ev_status *rp;
u8 *mode;

- BT_DBG("%s status 0x%2.2x", hdev->name, status);
+ rp = hci_cc_skb_pull(hdev, skb, HCI_OP_WRITE_SSP_DEBUG_MODE,
+ sizeof(*rp));
+ if (!rp)
+ return;

- if (status)
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
return;

mode = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE);
@@ -3334,12 +3730,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb)
{
- struct hci_ev_cmd_complete *ev = (void *) skb->data;
+ struct hci_ev_cmd_complete *ev;

- *opcode = __le16_to_cpu(ev->opcode);
- *status = skb->data[sizeof(*ev)];
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CMD_COMPLETE, sizeof(*ev));
+ if (!ev)
+ return;

- skb_pull(skb, sizeof(*ev));
+ *opcode = __le16_to_cpu(ev->opcode);
+ *status = skb->data[0];

switch (*opcode) {
case HCI_OP_INQUIRY_CANCEL:
@@ -6196,13 +6594,9 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
if (!skb)
return false;

- if (skb->len < sizeof(*hdr)) {
- bt_dev_err(hdev, "too short HCI event");
+ hdr = hci_ev_skb_pull(hdev, skb, event, sizeof(*hdr));
+ if (!hdr)
return false;
- }
-
- hdr = (void *) skb->data;
- skb_pull(skb, HCI_EVENT_HDR_SIZE);

if (event) {
if (hdr->evt != event)
@@ -6222,13 +6616,9 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
return false;
}

- if (skb->len < sizeof(*ev)) {
- bt_dev_err(hdev, "too short cmd_complete event");
+ ev = hci_cc_skb_pull(hdev, skb, opcode, sizeof(*ev));
+ if (!ev)
return false;
- }
-
- ev = (void *) skb->data;
- skb_pull(skb, sizeof(*ev));

if (opcode != __le16_to_cpu(ev->opcode)) {
BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
@@ -6314,9 +6704,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete_t req_complete = NULL;
hci_req_complete_skb_t req_complete_skb = NULL;
struct sk_buff *orig_skb = NULL;
- u8 status = 0, event = hdr->evt, req_evt = 0;
+ u8 status = 0, event, req_evt = 0;
u16 opcode = HCI_OP_NOP;

+ if (skb->len < sizeof(*hdr)) {
+ bt_dev_err(hdev, "Malformed HCI Event");
+ goto done;
+ }
+
+ event = hdr->evt;
if (!event) {
bt_dev_warn(hdev, "Received unexpected HCI Event 00000000");
goto done;
--
2.30.2

2021-04-19 20:37:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 07/10] Bluetooth: HCI: Use skb_pull to parse LE Metaevents

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the LE Metaevents received have the minimum
required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
net/bluetooth/hci_event.c | 75 +++++++++++++++++++++++++++++++++------
1 file changed, 64 insertions(+), 11 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9776c395412c..dc39861f4da6 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -78,6 +78,18 @@ static void *hci_cc_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
return data;
}

+static void *hci_le_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
+ u8 ev, size_t len)
+{
+ void *data;
+
+ data = hci_skb_pull(skb, len);
+ if (!data)
+ bt_dev_err(hdev, "Malformed LE Event: 0x%2.2x", ev);
+
+ return data;
+}
+
static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
u8 *new_status)
{
@@ -5862,7 +5874,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,

static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_le_conn_complete *ev = (void *) skb->data;
+ struct hci_ev_le_conn_complete *ev;
+
+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_CONN_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

@@ -5876,7 +5893,12 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_le_enh_conn_complete *ev = (void *) skb->data;
+ struct hci_ev_le_enh_conn_complete *ev;
+
+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_ENHANCED_CONN_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;

BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

@@ -5894,9 +5916,14 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev,

static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_evt_le_ext_adv_set_term *ev = (void *) skb->data;
+ struct hci_evt_le_ext_adv_set_term *ev;
struct hci_conn *conn;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_EXT_ADV_SET_TERM,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

if (ev->status)
@@ -5923,9 +5950,14 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_le_conn_update_complete *ev = (void *) skb->data;
+ struct hci_ev_le_conn_update_complete *ev;
struct hci_conn *conn;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_CONN_UPDATE_COMPLETE,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

if (ev->status)
@@ -6340,9 +6372,14 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_le_remote_feat_complete *ev = (void *)skb->data;
+ struct hci_ev_le_remote_feat_complete *ev;
struct hci_conn *conn;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_EXT_ADV_REPORT,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

hci_dev_lock(hdev);
@@ -6381,12 +6418,16 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev,

static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_le_ltk_req *ev = (void *) skb->data;
+ struct hci_ev_le_ltk_req *ev;
struct hci_cp_le_ltk_reply cp;
struct hci_cp_le_ltk_neg_reply neg;
struct hci_conn *conn;
struct smp_ltk *ltk;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_LTK_REQ, sizeof(*ev));
+ if (!ev)
+ return;
+
BT_DBG("%s handle 0x%4.4x", hdev->name, __le16_to_cpu(ev->handle));

hci_dev_lock(hdev);
@@ -6458,11 +6499,16 @@ static void send_conn_param_neg_reply(struct hci_dev *hdev, u16 handle,
static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_le_remote_conn_param_req *ev = (void *) skb->data;
+ struct hci_ev_le_remote_conn_param_req *ev;
struct hci_cp_le_conn_param_req_reply cp;
struct hci_conn *hcon;
u16 handle, min, max, latency, timeout;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_REMOTE_CONN_PARAM_REQ,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
handle = le16_to_cpu(ev->handle);
min = le16_to_cpu(ev->interval_min);
max = le16_to_cpu(ev->interval_max);
@@ -6535,9 +6581,14 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,

static void hci_le_phy_update_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_le_phy_update_complete *ev = (void *) skb->data;
+ struct hci_ev_le_phy_update_complete *ev;
struct hci_conn *conn;

+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_PHY_UPDATE_COMPLETE,
+ sizeof(*ev));
+ if (ev)
+ return;
+
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

if (ev->status)
@@ -6558,11 +6609,13 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, struct sk_buff *skb)

static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_ev_le_meta *le_ev = (void *) skb->data;
+ struct hci_ev_le_meta *ev;

- skb_pull(skb, sizeof(*le_ev));
+ ev = hci_ev_skb_pull(hdev, skb, HCI_EV_LE_META, sizeof(*ev));
+ if (!ev)
+ return;

- switch (le_ev->subevent) {
+ switch (ev->subevent) {
case HCI_EV_LE_CONN_COMPLETE:
hci_le_conn_complete_evt(hdev, skb);
break;
--
2.30.2

2021-04-19 20:37:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 10/10] Bluetooth: HCI: Use skb_pull to parse LE Direct Advertising Report event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the LE Direct Advertising Report events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 7 ++++++-
net/bluetooth/hci_event.c | 26 +++++++++++++++++++-------
2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 9600cc6ad952..13b7c7747bd1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2382,7 +2382,7 @@ struct hci_ev_le_data_len_change {

#define HCI_EV_LE_DIRECT_ADV_REPORT 0x0B
struct hci_ev_le_direct_adv_info {
- __u8 evt_type;
+ __u8 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 direct_addr_type;
@@ -2390,6 +2390,11 @@ struct hci_ev_le_direct_adv_info {
__s8 rssi;
} __packed;

+struct hci_ev_le_direct_adv_report {
+ __u8 num;
+ struct hci_ev_le_direct_adv_info info[];
+} __packed;
+
#define HCI_EV_LE_PHY_UPDATE_COMPLETE 0x0c
struct hci_ev_le_phy_update_complete {
__u8 status;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6aa05d7364bc..18788687567e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6591,19 +6591,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- u8 num_reports = skb->data[0];
- struct hci_ev_le_direct_adv_info *ev = (void *)&skb->data[1];
+ struct hci_ev_le_direct_adv_report *ev;
+ int i;
+
+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_DIRECT_ADV_REPORT,
+ sizeof(*ev));
+ if (!ev)
+ return;

- if (!num_reports || skb->len < num_reports * sizeof(*ev) + 1)
+ if (!hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_DIRECT_ADV_REPORT,
+ flex_array_size(ev, info, ev->num)))
+ return;
+
+ if (!ev->num)
return;

hci_dev_lock(hdev);

- for (; num_reports; num_reports--, ev++)
- process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
- ev->bdaddr_type, &ev->direct_addr,
- ev->direct_addr_type, ev->rssi, NULL, 0,
+ for (i = 0; i < ev->num; i++) {
+ struct hci_ev_le_direct_adv_info *info = &ev->info[i];
+
+ process_adv_report(hdev, info->type, &info->bdaddr,
+ info->bdaddr_type, &info->direct_addr,
+ info->direct_addr_type, info->rssi, NULL, 0,
false);
+ }

hci_dev_unlock(hdev);
}
--
2.30.2

2021-04-19 20:37:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 09/10] Bluetooth: HCI: Use skb_pull to parse LE Extended Advertising Report event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the LE Extended Advertising Report events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 17 +++++++++++------
net/bluetooth/hci_event.c | 36 +++++++++++++++++++++++++-----------
2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3ec8e07f1724..9600cc6ad952 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2399,8 +2399,8 @@ struct hci_ev_le_phy_update_complete {
} __packed;

#define HCI_EV_LE_EXT_ADV_REPORT 0x0d
-struct hci_ev_le_ext_adv_report {
- __le16 evt_type;
+struct hci_ev_le_ext_adv_info {
+ __le16 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 primary_phy;
@@ -2408,11 +2408,16 @@ struct hci_ev_le_ext_adv_report {
__u8 sid;
__u8 tx_power;
__s8 rssi;
- __le16 interval;
- __u8 direct_addr_type;
+ __le16 interval;
+ __u8 direct_addr_type;
bdaddr_t direct_addr;
- __u8 length;
- __u8 data[];
+ __u8 length;
+ __u8 data[];
+} __packed;
+
+struct hci_ev_le_ext_adv_report {
+ __u8 num;
+ struct hci_ev_le_ext_adv_info info[];
} __packed;

#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 69a5296382ae..6aa05d7364bc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6359,26 +6359,40 @@ static u8 ext_evt_type_to_legacy(struct hci_dev *hdev, u16 evt_type)

static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- u8 num_reports = skb->data[0];
- void *ptr = &skb->data[1];
+ struct hci_ev_le_ext_adv_report *ev;
+
+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_EXT_ADV_REPORT,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
+ if (!ev->num)
+ return;

hci_dev_lock(hdev);

- while (num_reports--) {
- struct hci_ev_le_ext_adv_report *ev = ptr;
+ while (ev->num--) {
+ struct hci_ev_le_ext_adv_info *info;
u8 legacy_evt_type;
u16 evt_type;

- evt_type = __le16_to_cpu(ev->evt_type);
+ info = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_EXT_ADV_REPORT,
+ sizeof(*info));
+ if (!info)
+ break;
+
+ if (!hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_EXT_ADV_REPORT,
+ info->length))
+ break;
+
+ evt_type = __le16_to_cpu(info->type);
legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type);
if (legacy_evt_type != LE_ADV_INVALID) {
- process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
- ev->bdaddr_type, NULL, 0, ev->rssi,
- ev->data, ev->length,
+ process_adv_report(hdev, legacy_evt_type, &info->bdaddr,
+ info->bdaddr_type, NULL, 0,
+ info->rssi, info->data, info->length,
!(evt_type & LE_EXT_ADV_LEGACY_PDU));
}
-
- ptr += sizeof(*ev) + ev->length;
}

hci_dev_unlock(hdev);
@@ -6729,7 +6743,7 @@ static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
{
struct hci_ev_le_advertising_info *adv;
struct hci_ev_le_direct_adv_info *direct_adv;
- struct hci_ev_le_ext_adv_report *ext_adv;
+ struct hci_ev_le_ext_adv_info *ext_adv;
const struct hci_ev_conn_complete *conn_complete = (void *)skb->data;
const struct hci_ev_conn_request *conn_request = (void *)skb->data;

--
2.30.2

2021-04-19 22:11:06

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH v2 08/10] Bluetooth: HCI: Use skb_pull to parse LE Advertising Report event

From: Luiz Augusto von Dentz <[email protected]>

This uses skb_pull to check the LE Advertising Report events received
have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci.h | 7 ++++++-
net/bluetooth/hci_event.c | 37 ++++++++++++++++++++++++++-----------
2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index f416ad71fd2d..3ec8e07f1724 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2327,13 +2327,18 @@ struct hci_ev_le_conn_complete {

#define HCI_EV_LE_ADVERTISING_REPORT 0x02
struct hci_ev_le_advertising_info {
- __u8 evt_type;
+ __u8 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 length;
__u8 data[];
} __packed;

+struct hci_ev_le_advertising_report {
+ __u8 num;
+ struct hci_ev_le_advertising_info info[];
+} __packed;
+
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
struct hci_ev_le_conn_update_complete {
__u8 status;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index dc39861f4da6..69a5296382ae 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6274,25 +6274,40 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,

static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
- u8 num_reports = skb->data[0];
- void *ptr = &skb->data[1];
+ struct hci_ev_le_advertising_report *ev;
+
+ ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_ADVERTISING_REPORT,
+ sizeof(*ev));
+ if (!ev)
+ return;
+
+ if (!ev->num)
+ return;

hci_dev_lock(hdev);

- while (num_reports--) {
- struct hci_ev_le_advertising_info *ev = ptr;
+ while (ev->num--) {
+ struct hci_ev_le_advertising_info *info;
s8 rssi;

- if (ev->length <= HCI_MAX_AD_LENGTH) {
- rssi = ev->data[ev->length];
- process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
- ev->bdaddr_type, NULL, 0, rssi,
- ev->data, ev->length, false);
+ info = hci_le_ev_skb_pull(hdev, skb,
+ HCI_EV_LE_ADVERTISING_REPORT,
+ sizeof(*info));
+ if (!info)
+ break;
+
+ if (!hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_ADVERTISING_REPORT,
+ info->length + 1))
+ break;
+
+ if (info->length <= HCI_MAX_AD_LENGTH) {
+ rssi = info->data[info->length];
+ process_adv_report(hdev, info->type, &info->bdaddr,
+ info->bdaddr_type, NULL, 0, rssi,
+ info->data, info->length, false);
} else {
bt_dev_err(hdev, "Dropping invalid advertising data");
}
-
- ptr += sizeof(*ev) + ev->length + 1;
}

hci_dev_unlock(hdev);
--
2.30.2

2021-04-19 22:13:28

by bluez.test.bot

[permalink] [raw]
Subject: RE: Bluetooth: HCI: Use skb_pull to parse events

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=469803

---Test result---

##############################
Test: CheckPatch - PASS


##############################
Test: CheckGitLint - FAIL
Bluetooth: HCI: Use skb_pull to parse LE Extended Advertising Report event
1: T1 Title exceeds max length (74>72): "Bluetooth: HCI: Use skb_pull to parse LE Extended Advertising Report event"


##############################
Test: CheckBuildK - PASS


##############################
Test: CheckTestRunner: Setup - PASS


##############################
Test: CheckTestRunner: l2cap-tester - PASS
Total: 40, Passed: 34 (85.0%), Failed: 0, Not Run: 6

##############################
Test: CheckTestRunner: bnep-tester - PASS
Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: mgmt-tester - PASS
Total: 416, Passed: 402 (96.6%), Failed: 0, Not Run: 14

##############################
Test: CheckTestRunner: rfcomm-tester - PASS
Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: sco-tester - PASS
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: smp-tester - PASS
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: userchan-tester - PASS
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0



---
Regards,
Linux Bluetooth


Attachments:
l2cap-tester.log (42.33 kB)
bnep-tester.log (3.45 kB)
mgmt-tester.log (533.92 kB)
rfcomm-tester.log (11.38 kB)
sco-tester.log (9.66 kB)
smp-tester.log (11.53 kB)
userchan-tester.log (5.31 kB)
Download all attachments

2021-04-23 12:28:36

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Luiz,

> This uses skb_pull to check the BR/EDR events received have the minimum
> required length.
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> include/net/bluetooth/hci.h | 4 +
> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
> 2 files changed, 229 insertions(+), 47 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index ea4ae551c426..f1f505355e81 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
> } __packed;
>
> /* ---- HCI Events ---- */
> +struct hci_ev_status {
> + __u8 status;
> +} __packed;
> +
> #define HCI_EV_INQUIRY_COMPLETE 0x01
>
> #define HCI_EV_INQUIRY_RESULT 0x02
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 5e99968939ce..077541fcba41 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -42,6 +42,30 @@
>
> /* Handle HCI Event packets */
>
> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
> +{
> + void *data = skb->data;
> +
> + if (skb->len < len)
> + return NULL;
> +
> + skb_pull(skb, len);
> +
> + return data;
> +}
> +
> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
> + u8 ev, size_t len)
> +{
> + void *data;
> +
> + data = hci_skb_pull(skb, len);
> + if (!data)
> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
> +
> + return data;
> +}
> +

so if you do it in one function, this will look like this:

static void *hci_ev_skb_pull(..)
{
void *data = skb->data;

if (skb->len < len) {
bt_dev_err(hdev, “Malformed ..”);
return NULL;
}

skb_pull(skb, len);
return data;
}

static void *hci_cc_skb_pull(..)
{
void *data = skb->data;

if (skb->len < len) {
bt_dev_err(..);
return NULL;
}

skb_pull(..);
return data;
}

I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.



> static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
> u8 *new_status)
> {
> @@ -2507,11 +2531,15 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
>
> static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> - __u8 status = *((__u8 *) skb->data);
> + struct hci_ev_status *ev;
> struct discovery_state *discov = &hdev->discovery;
> struct inquiry_entry *e;
>
> - BT_DBG("%s status 0x%2.2x", hdev->name, status);
> + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_COMPLETE, sizeof(*ev));
> + if (!ev)
> + return;
> +

Now since we also have this pattern:

ev = hci_ev_skb_pull(..);
if (!ev)
return;

The question is now why not just use a #define here.

hci_ev_skb_pull(HCI_EV_INQUIRY_COMPLETE, ev);

And then the define would look like this (untested):

#define hci_ev_skb_pull(evt, var) do { \
(var) = skb->data; \
if (skb->len < sizeof(*(var))) { \
bt_dev_err(hdev, “Malformed ..”); \
return NULL; \
} \
skb_pull(skb, sizeof(*(var))); \
} while (0);


> + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

If we have every event with an ev->status, we could even include bt_dev_dbg in the macro.

>
> hci_conn_check_pending(hdev);
>
> @@ -2604,9 +2632,13 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> - struct hci_ev_conn_complete *ev = (void *) skb->data;
> + struct hci_ev_conn_complete *ev;
> struct hci_conn *conn;
>
> + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CONN_COMPLETE, sizeof(*ev));
> + if (!ev)
> + return;
> +
> BT_DBG("%s", hdev->name);

If you are touching the above part anyway, then move towards bt_dev_dbg() at the same time.

Regards

Marcel

2021-04-23 12:29:49

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 04/10] Bluetooth: HCI: Use skb_pull to parse Inquiry Result event

Hi Luiz,

> This uses skb_pull to check the Inquiry Result events received have
> the minimum required length.
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> include/net/bluetooth/hci.h | 5 +++++
> net/bluetooth/hci_event.c | 19 ++++++++++++++-----
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 9251ae3a2ce0..b65205b4d830 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1910,6 +1910,11 @@ struct inquiry_info {
> __le16 clock_offset;
> } __packed;
>
> +struct hci_ev_inquiry_result {
> + __u8 num;
> + struct inquiry_info info[];
> +};
> +
> #define HCI_EV_CONN_COMPLETE 0x03
> struct hci_ev_conn_complete {
> __u8 status;
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index c353dfafb04c..6516538fe238 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2990,13 +2990,21 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> + struct hci_ev_inquiry_result *ev;
> struct inquiry_data data;
> - struct inquiry_info *info = (void *) (skb->data + 1);
> - int num_rsp = *((__u8 *) skb->data);
> + int i;
>
> - BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
> + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_RESULT, sizeof(*ev));
> + if (!ev)
> + return;
>
> - if (!num_rsp || skb->len < num_rsp * sizeof(*info) + 1)
> + if (!hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_RESULT,
> + flex_array_size(ev, info, ev->num)))
> + return;
> +
> + BT_DBG("%s num %d", hdev->name, ev->num);

please switch to bt_dev_dbg() here.

Regards

Marcel

2021-04-23 12:31:59

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 03/10] Bluetooth: HCI: Use skb_pull to parse Number of Complete Packets event

Hi Luiz,

> This uses skb_pull to check the Number of Complete Packets events
> received have the minimum required length.
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> include/net/bluetooth/hci.h | 2 +-
> net/bluetooth/hci_event.c | 20 +++++++++++---------
> 2 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index f1f505355e81..9251ae3a2ce0 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -2021,7 +2021,7 @@ struct hci_comp_pkts_info {
> } __packed;
>
> struct hci_ev_num_comp_pkts {
> - __u8 num_hndl;
> + __u8 num;
> struct hci_comp_pkts_info handles[];
> } __packed;
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index cc2d68389edc..c353dfafb04c 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -4264,23 +4264,25 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> - struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
> + struct hci_ev_num_comp_pkts *ev;
> int i;
>
> - if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
> - bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
> + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_PKTS, sizeof(*ev));
> + if (!ev)
> return;
> - }
>
> - if (skb->len < sizeof(*ev) ||
> - skb->len < struct_size(ev, handles, ev->num_hndl)) {
> - BT_DBG("%s bad parameters", hdev->name);
> + if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_PKTS,
> + flex_array_size(ev, handles, ev->num)))
> + return;
> +
> + if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
> + bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode);
> return;
> }
>
> - BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
> + BT_DBG("%s num %d", hdev->name, ev->num);

If you are touching BT_DBG anyway then switch to bt_dev_dbg() please.

Regards

Marcel

2021-04-26 21:52:56

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Marcel,

On Fri, Apr 23, 2021 at 5:26 AM Marcel Holtmann <[email protected]> wrote:
>
> Hi Luiz,
>
> > This uses skb_pull to check the BR/EDR events received have the minimum
> > required length.
> >
> > Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> > ---
> > include/net/bluetooth/hci.h | 4 +
> > net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
> > 2 files changed, 229 insertions(+), 47 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index ea4ae551c426..f1f505355e81 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
> > } __packed;
> >
> > /* ---- HCI Events ---- */
> > +struct hci_ev_status {
> > + __u8 status;
> > +} __packed;
> > +
> > #define HCI_EV_INQUIRY_COMPLETE 0x01
> >
> > #define HCI_EV_INQUIRY_RESULT 0x02
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > index 5e99968939ce..077541fcba41 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -42,6 +42,30 @@
> >
> > /* Handle HCI Event packets */
> >
> > +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
> > +{
> > + void *data = skb->data;
> > +
> > + if (skb->len < len)
> > + return NULL;
> > +
> > + skb_pull(skb, len);
> > +
> > + return data;
> > +}
> > +
> > +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
> > + u8 ev, size_t len)
> > +{
> > + void *data;
> > +
> > + data = hci_skb_pull(skb, len);
> > + if (!data)
> > + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
> > +
> > + return data;
> > +}
> > +
>
> so if you do it in one function, this will look like this:
>
> static void *hci_ev_skb_pull(..)
> {
> void *data = skb->data;
>
> if (skb->len < len) {
> bt_dev_err(hdev, “Malformed ..”);
> return NULL;
> }
>
> skb_pull(skb, len);
> return data;
> }
>
> static void *hci_cc_skb_pull(..)
> {
> void *data = skb->data;
>
> if (skb->len < len) {
> bt_dev_err(..);
> return NULL;
> }
>
> skb_pull(..);
> return data;
> }
>
> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.

Right, I can either do that or perhaps bite the bullet and convert the
whole hci_event.c to use a function table:

#define HCI_EVENT(_op, _len, _func)...

struct hci_event {
__u8 op;
__u16 len;
func...
} ev_table[] = {
HCI_EVENT(...),
}

But that would pack a lot more changes since we would need to convert
the whole switch to a for loop or alternatively if we don't want do a
lookup we could omit the op and access the table by index if we want
to trade speed over code size, with that we can have just one call to
the likes of hci_ev_skb_pull.

>
>
> > static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb,
> > u8 *new_status)
> > {
> > @@ -2507,11 +2531,15 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
> >
> > static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> > - __u8 status = *((__u8 *) skb->data);
> > + struct hci_ev_status *ev;
> > struct discovery_state *discov = &hdev->discovery;
> > struct inquiry_entry *e;
> >
> > - BT_DBG("%s status 0x%2.2x", hdev->name, status);
> > + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_INQUIRY_COMPLETE, sizeof(*ev));
> > + if (!ev)
> > + return;
> > +
>
> Now since we also have this pattern:
>
> ev = hci_ev_skb_pull(..);
> if (!ev)
> return;
>
> The question is now why not just use a #define here.
>
> hci_ev_skb_pull(HCI_EV_INQUIRY_COMPLETE, ev);
>
> And then the define would look like this (untested):
>
> #define hci_ev_skb_pull(evt, var) do { \
> (var) = skb->data; \
> if (skb->len < sizeof(*(var))) { \
> bt_dev_err(hdev, “Malformed ..”); \
> return NULL; \
> } \
> skb_pull(skb, sizeof(*(var))); \
> } while (0);
>
>
> > + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
>
> If we have every event with an ev->status, we could even include bt_dev_dbg in the macro.
>
> >
> > hci_conn_check_pending(hdev);
> >
> > @@ -2604,9 +2632,13 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
> >
> > static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> > - struct hci_ev_conn_complete *ev = (void *) skb->data;
> > + struct hci_ev_conn_complete *ev;
> > struct hci_conn *conn;
> >
> > + ev = hci_ev_skb_pull(hdev, skb, HCI_EV_CONN_COMPLETE, sizeof(*ev));
> > + if (!ev)
> > + return;
> > +
> > BT_DBG("%s", hdev->name);
>
> If you are touching the above part anyway, then move towards bt_dev_dbg() at the same time.
>
> Regards
>
> Marcel
>


--
Luiz Augusto von Dentz

2021-04-27 06:09:01

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Luiz,

>>> This uses skb_pull to check the BR/EDR events received have the minimum
>>> required length.
>>>
>>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
>>> ---
>>> include/net/bluetooth/hci.h | 4 +
>>> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
>>> 2 files changed, 229 insertions(+), 47 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>> index ea4ae551c426..f1f505355e81 100644
>>> --- a/include/net/bluetooth/hci.h
>>> +++ b/include/net/bluetooth/hci.h
>>> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
>>> } __packed;
>>>
>>> /* ---- HCI Events ---- */
>>> +struct hci_ev_status {
>>> + __u8 status;
>>> +} __packed;
>>> +
>>> #define HCI_EV_INQUIRY_COMPLETE 0x01
>>>
>>> #define HCI_EV_INQUIRY_RESULT 0x02
>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>> index 5e99968939ce..077541fcba41 100644
>>> --- a/net/bluetooth/hci_event.c
>>> +++ b/net/bluetooth/hci_event.c
>>> @@ -42,6 +42,30 @@
>>>
>>> /* Handle HCI Event packets */
>>>
>>> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
>>> +{
>>> + void *data = skb->data;
>>> +
>>> + if (skb->len < len)
>>> + return NULL;
>>> +
>>> + skb_pull(skb, len);
>>> +
>>> + return data;
>>> +}
>>> +
>>> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
>>> + u8 ev, size_t len)
>>> +{
>>> + void *data;
>>> +
>>> + data = hci_skb_pull(skb, len);
>>> + if (!data)
>>> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
>>> +
>>> + return data;
>>> +}
>>> +
>>
>> so if you do it in one function, this will look like this:
>>
>> static void *hci_ev_skb_pull(..)
>> {
>> void *data = skb->data;
>>
>> if (skb->len < len) {
>> bt_dev_err(hdev, “Malformed ..”);
>> return NULL;
>> }
>>
>> skb_pull(skb, len);
>> return data;
>> }
>>
>> static void *hci_cc_skb_pull(..)
>> {
>> void *data = skb->data;
>>
>> if (skb->len < len) {
>> bt_dev_err(..);
>> return NULL;
>> }
>>
>> skb_pull(..);
>> return data;
>> }
>>
>> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.
>
> Right, I can either do that or perhaps bite the bullet and convert the
> whole hci_event.c to use a function table:
>
> #define HCI_EVENT(_op, _len, _func)...
>
> struct hci_event {
> __u8 op;
> __u16 len;
> func...
> } ev_table[] = {
> HCI_EVENT(...),
> }
>
> But that would pack a lot more changes since we would need to convert
> the whole switch to a for loop or alternatively if we don't want do a
> lookup we could omit the op and access the table by index if we want
> to trade speed over code size, with that we can have just one call to
> the likes of hci_ev_skb_pull.

looping through a table is not ideal. There are too many events that you can receive and if we end up looping for every LE advertising report it would be rather silly. And of course a static table is possible since event numbers are assigned in order, but it also means some sort of overhead since we don’t parse each event.

In addition to that dilemma, you have the problem that not all events are fixed size. So you end up indicating that similar to how we do it in btmon which will increase the table size again. Maybe that is actually ok since two giant switch statements also take time and code size.

So our currently max event code is 0x57 for Authenticated Payload Timeout and the max LE event code is 0x3e for BIG Info Advertising Report. Meaning table one would have 87 entries and table would have two 63 entries. If we do min_len,max_len as uint8 then we have 2 octets and a function pointer. Maybe that is not too bad since that is all static const data.

Regards

Marcel

2021-04-27 17:59:07

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Marcel,

On Mon, Apr 26, 2021 at 11:07 PM Marcel Holtmann <[email protected]> wrote:
>
> Hi Luiz,
>
> >>> This uses skb_pull to check the BR/EDR events received have the minimum
> >>> required length.
> >>>
> >>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> >>> ---
> >>> include/net/bluetooth/hci.h | 4 +
> >>> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
> >>> 2 files changed, 229 insertions(+), 47 deletions(-)
> >>>
> >>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> >>> index ea4ae551c426..f1f505355e81 100644
> >>> --- a/include/net/bluetooth/hci.h
> >>> +++ b/include/net/bluetooth/hci.h
> >>> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
> >>> } __packed;
> >>>
> >>> /* ---- HCI Events ---- */
> >>> +struct hci_ev_status {
> >>> + __u8 status;
> >>> +} __packed;
> >>> +
> >>> #define HCI_EV_INQUIRY_COMPLETE 0x01
> >>>
> >>> #define HCI_EV_INQUIRY_RESULT 0x02
> >>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> >>> index 5e99968939ce..077541fcba41 100644
> >>> --- a/net/bluetooth/hci_event.c
> >>> +++ b/net/bluetooth/hci_event.c
> >>> @@ -42,6 +42,30 @@
> >>>
> >>> /* Handle HCI Event packets */
> >>>
> >>> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
> >>> +{
> >>> + void *data = skb->data;
> >>> +
> >>> + if (skb->len < len)
> >>> + return NULL;
> >>> +
> >>> + skb_pull(skb, len);
> >>> +
> >>> + return data;
> >>> +}
> >>> +
> >>> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
> >>> + u8 ev, size_t len)
> >>> +{
> >>> + void *data;
> >>> +
> >>> + data = hci_skb_pull(skb, len);
> >>> + if (!data)
> >>> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
> >>> +
> >>> + return data;
> >>> +}
> >>> +
> >>
> >> so if you do it in one function, this will look like this:
> >>
> >> static void *hci_ev_skb_pull(..)
> >> {
> >> void *data = skb->data;
> >>
> >> if (skb->len < len) {
> >> bt_dev_err(hdev, “Malformed ..”);
> >> return NULL;
> >> }
> >>
> >> skb_pull(skb, len);
> >> return data;
> >> }
> >>
> >> static void *hci_cc_skb_pull(..)
> >> {
> >> void *data = skb->data;
> >>
> >> if (skb->len < len) {
> >> bt_dev_err(..);
> >> return NULL;
> >> }
> >>
> >> skb_pull(..);
> >> return data;
> >> }
> >>
> >> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.
> >
> > Right, I can either do that or perhaps bite the bullet and convert the
> > whole hci_event.c to use a function table:
> >
> > #define HCI_EVENT(_op, _len, _func)...
> >
> > struct hci_event {
> > __u8 op;
> > __u16 len;
> > func...
> > } ev_table[] = {
> > HCI_EVENT(...),
> > }
> >
> > But that would pack a lot more changes since we would need to convert
> > the whole switch to a for loop or alternatively if we don't want do a
> > lookup we could omit the op and access the table by index if we want
> > to trade speed over code size, with that we can have just one call to
> > the likes of hci_ev_skb_pull.
>
> looping through a table is not ideal. There are too many events that you can receive and if we end up looping for every LE advertising report it would be rather silly. And of course a static table is possible since event numbers are assigned in order, but it also means some sort of overhead since we don’t parse each event.
>
> In addition to that dilemma, you have the problem that not all events are fixed size. So you end up indicating that similar to how we do it in btmon which will increase the table size again. Maybe that is actually ok since two giant switch statements also take time and code size.
>
> So our currently max event code is 0x57 for Authenticated Payload Timeout and the max LE event code is 0x3e for BIG Info Advertising Report. Meaning table one would have 87 entries and table would have two 63 entries. If we do min_len,max_len as uint8 then we have 2 octets and a function pointer. Maybe that is not too bad since that is all static const data.

Yep, even if we have to have NOP for those event we don't handle I
don't think it is such a big deal and accessing by index should be
comparable in terms of speed to a switch statement, that said we may
still need to do some checks on the callbacks for those events that
have variable size I was only intending to do minimal size checks but
perhaps you are saying it might be better to have a bool/flag saying
that the event has variable size which matters when we are checking
the length to either use == or <.

> Regards
>
> Marcel
>


--
Luiz Augusto von Dentz

2021-04-27 18:39:35

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Luiz,

>>>>> This uses skb_pull to check the BR/EDR events received have the minimum
>>>>> required length.
>>>>>
>>>>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
>>>>> ---
>>>>> include/net/bluetooth/hci.h | 4 +
>>>>> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
>>>>> 2 files changed, 229 insertions(+), 47 deletions(-)
>>>>>
>>>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>>>> index ea4ae551c426..f1f505355e81 100644
>>>>> --- a/include/net/bluetooth/hci.h
>>>>> +++ b/include/net/bluetooth/hci.h
>>>>> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
>>>>> } __packed;
>>>>>
>>>>> /* ---- HCI Events ---- */
>>>>> +struct hci_ev_status {
>>>>> + __u8 status;
>>>>> +} __packed;
>>>>> +
>>>>> #define HCI_EV_INQUIRY_COMPLETE 0x01
>>>>>
>>>>> #define HCI_EV_INQUIRY_RESULT 0x02
>>>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>>>> index 5e99968939ce..077541fcba41 100644
>>>>> --- a/net/bluetooth/hci_event.c
>>>>> +++ b/net/bluetooth/hci_event.c
>>>>> @@ -42,6 +42,30 @@
>>>>>
>>>>> /* Handle HCI Event packets */
>>>>>
>>>>> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
>>>>> +{
>>>>> + void *data = skb->data;
>>>>> +
>>>>> + if (skb->len < len)
>>>>> + return NULL;
>>>>> +
>>>>> + skb_pull(skb, len);
>>>>> +
>>>>> + return data;
>>>>> +}
>>>>> +
>>>>> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
>>>>> + u8 ev, size_t len)
>>>>> +{
>>>>> + void *data;
>>>>> +
>>>>> + data = hci_skb_pull(skb, len);
>>>>> + if (!data)
>>>>> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
>>>>> +
>>>>> + return data;
>>>>> +}
>>>>> +
>>>>
>>>> so if you do it in one function, this will look like this:
>>>>
>>>> static void *hci_ev_skb_pull(..)
>>>> {
>>>> void *data = skb->data;
>>>>
>>>> if (skb->len < len) {
>>>> bt_dev_err(hdev, “Malformed ..”);
>>>> return NULL;
>>>> }
>>>>
>>>> skb_pull(skb, len);
>>>> return data;
>>>> }
>>>>
>>>> static void *hci_cc_skb_pull(..)
>>>> {
>>>> void *data = skb->data;
>>>>
>>>> if (skb->len < len) {
>>>> bt_dev_err(..);
>>>> return NULL;
>>>> }
>>>>
>>>> skb_pull(..);
>>>> return data;
>>>> }
>>>>
>>>> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.
>>>
>>> Right, I can either do that or perhaps bite the bullet and convert the
>>> whole hci_event.c to use a function table:
>>>
>>> #define HCI_EVENT(_op, _len, _func)...
>>>
>>> struct hci_event {
>>> __u8 op;
>>> __u16 len;
>>> func...
>>> } ev_table[] = {
>>> HCI_EVENT(...),
>>> }
>>>
>>> But that would pack a lot more changes since we would need to convert
>>> the whole switch to a for loop or alternatively if we don't want do a
>>> lookup we could omit the op and access the table by index if we want
>>> to trade speed over code size, with that we can have just one call to
>>> the likes of hci_ev_skb_pull.
>>
>> looping through a table is not ideal. There are too many events that you can receive and if we end up looping for every LE advertising report it would be rather silly. And of course a static table is possible since event numbers are assigned in order, but it also means some sort of overhead since we don’t parse each event.
>>
>> In addition to that dilemma, you have the problem that not all events are fixed size. So you end up indicating that similar to how we do it in btmon which will increase the table size again. Maybe that is actually ok since two giant switch statements also take time and code size.
>>
>> So our currently max event code is 0x57 for Authenticated Payload Timeout and the max LE event code is 0x3e for BIG Info Advertising Report. Meaning table one would have 87 entries and table would have two 63 entries. If we do min_len,max_len as uint8 then we have 2 octets and a function pointer. Maybe that is not too bad since that is all static const data.
>
> Yep, even if we have to have NOP for those event we don't handle I
> don't think it is such a big deal and accessing by index should be
> comparable in terms of speed to a switch statement, that said we may
> still need to do some checks on the callbacks for those events that
> have variable size I was only intending to do minimal size checks but
> perhaps you are saying it might be better to have a bool/flag saying
> that the event has variable size which matters when we are checking
> the length to either use == or <.

I actually meant min_len + max_len.

So you have for example

HCI_EVENT(..) that sets min_len = x, max_len = x.
HCI_EVENT_VAR(..) that sets min_len = x and max_len = 253.

No need for extra flags then.

Regards

Marcel

2021-04-27 18:52:50

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Marcel,

On Tue, Apr 27, 2021 at 11:37 AM Marcel Holtmann <[email protected]> wrote:
>
> Hi Luiz,
>
> >>>>> This uses skb_pull to check the BR/EDR events received have the minimum
> >>>>> required length.
> >>>>>
> >>>>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> >>>>> ---
> >>>>> include/net/bluetooth/hci.h | 4 +
> >>>>> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
> >>>>> 2 files changed, 229 insertions(+), 47 deletions(-)
> >>>>>
> >>>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> >>>>> index ea4ae551c426..f1f505355e81 100644
> >>>>> --- a/include/net/bluetooth/hci.h
> >>>>> +++ b/include/net/bluetooth/hci.h
> >>>>> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
> >>>>> } __packed;
> >>>>>
> >>>>> /* ---- HCI Events ---- */
> >>>>> +struct hci_ev_status {
> >>>>> + __u8 status;
> >>>>> +} __packed;
> >>>>> +
> >>>>> #define HCI_EV_INQUIRY_COMPLETE 0x01
> >>>>>
> >>>>> #define HCI_EV_INQUIRY_RESULT 0x02
> >>>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> >>>>> index 5e99968939ce..077541fcba41 100644
> >>>>> --- a/net/bluetooth/hci_event.c
> >>>>> +++ b/net/bluetooth/hci_event.c
> >>>>> @@ -42,6 +42,30 @@
> >>>>>
> >>>>> /* Handle HCI Event packets */
> >>>>>
> >>>>> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
> >>>>> +{
> >>>>> + void *data = skb->data;
> >>>>> +
> >>>>> + if (skb->len < len)
> >>>>> + return NULL;
> >>>>> +
> >>>>> + skb_pull(skb, len);
> >>>>> +
> >>>>> + return data;
> >>>>> +}
> >>>>> +
> >>>>> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
> >>>>> + u8 ev, size_t len)
> >>>>> +{
> >>>>> + void *data;
> >>>>> +
> >>>>> + data = hci_skb_pull(skb, len);
> >>>>> + if (!data)
> >>>>> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
> >>>>> +
> >>>>> + return data;
> >>>>> +}
> >>>>> +
> >>>>
> >>>> so if you do it in one function, this will look like this:
> >>>>
> >>>> static void *hci_ev_skb_pull(..)
> >>>> {
> >>>> void *data = skb->data;
> >>>>
> >>>> if (skb->len < len) {
> >>>> bt_dev_err(hdev, “Malformed ..”);
> >>>> return NULL;
> >>>> }
> >>>>
> >>>> skb_pull(skb, len);
> >>>> return data;
> >>>> }
> >>>>
> >>>> static void *hci_cc_skb_pull(..)
> >>>> {
> >>>> void *data = skb->data;
> >>>>
> >>>> if (skb->len < len) {
> >>>> bt_dev_err(..);
> >>>> return NULL;
> >>>> }
> >>>>
> >>>> skb_pull(..);
> >>>> return data;
> >>>> }
> >>>>
> >>>> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.
> >>>
> >>> Right, I can either do that or perhaps bite the bullet and convert the
> >>> whole hci_event.c to use a function table:
> >>>
> >>> #define HCI_EVENT(_op, _len, _func)...
> >>>
> >>> struct hci_event {
> >>> __u8 op;
> >>> __u16 len;
> >>> func...
> >>> } ev_table[] = {
> >>> HCI_EVENT(...),
> >>> }
> >>>
> >>> But that would pack a lot more changes since we would need to convert
> >>> the whole switch to a for loop or alternatively if we don't want do a
> >>> lookup we could omit the op and access the table by index if we want
> >>> to trade speed over code size, with that we can have just one call to
> >>> the likes of hci_ev_skb_pull.
> >>
> >> looping through a table is not ideal. There are too many events that you can receive and if we end up looping for every LE advertising report it would be rather silly. And of course a static table is possible since event numbers are assigned in order, but it also means some sort of overhead since we don’t parse each event.
> >>
> >> In addition to that dilemma, you have the problem that not all events are fixed size. So you end up indicating that similar to how we do it in btmon which will increase the table size again. Maybe that is actually ok since two giant switch statements also take time and code size.
> >>
> >> So our currently max event code is 0x57 for Authenticated Payload Timeout and the max LE event code is 0x3e for BIG Info Advertising Report. Meaning table one would have 87 entries and table would have two 63 entries. If we do min_len,max_len as uint8 then we have 2 octets and a function pointer. Maybe that is not too bad since that is all static const data.
> >
> > Yep, even if we have to have NOP for those event we don't handle I
> > don't think it is such a big deal and accessing by index should be
> > comparable in terms of speed to a switch statement, that said we may
> > still need to do some checks on the callbacks for those events that
> > have variable size I was only intending to do minimal size checks but
> > perhaps you are saying it might be better to have a bool/flag saying
> > that the event has variable size which matters when we are checking
> > the length to either use == or <.
>
> I actually meant min_len + max_len.
>
> So you have for example
>
> HCI_EVENT(..) that sets min_len = x, max_len = x.
> HCI_EVENT_VAR(..) that sets min_len = x and max_len = 253.
>
> No need for extra flags then.

Ah got it, is there really a max_len for variable size though? Or you
mean to say that should be limited to event buffer size? That Im
afraid we only discover at runtime, anyway usually for variable size
we should be using flex_array_size but that requires accessing the
received skb so we can't really tell at build time and it will be
likely left for the callback to figure out it has received enough data
or not.

>
> Regards
>
> Marcel
>


--
Luiz Augusto von Dentz

2021-04-27 19:00:58

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 01/10] Bluetooth: HCI: Use skb_pull to parse BR/EDR events

Hi Luiz,

>>>>>>> This uses skb_pull to check the BR/EDR events received have the minimum
>>>>>>> required length.
>>>>>>>
>>>>>>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
>>>>>>> ---
>>>>>>> include/net/bluetooth/hci.h | 4 +
>>>>>>> net/bluetooth/hci_event.c | 272 +++++++++++++++++++++++++++++-------
>>>>>>> 2 files changed, 229 insertions(+), 47 deletions(-)
>>>>>>>
>>>>>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>>>>>> index ea4ae551c426..f1f505355e81 100644
>>>>>>> --- a/include/net/bluetooth/hci.h
>>>>>>> +++ b/include/net/bluetooth/hci.h
>>>>>>> @@ -1894,6 +1894,10 @@ struct hci_cp_le_reject_cis {
>>>>>>> } __packed;
>>>>>>>
>>>>>>> /* ---- HCI Events ---- */
>>>>>>> +struct hci_ev_status {
>>>>>>> + __u8 status;
>>>>>>> +} __packed;
>>>>>>> +
>>>>>>> #define HCI_EV_INQUIRY_COMPLETE 0x01
>>>>>>>
>>>>>>> #define HCI_EV_INQUIRY_RESULT 0x02
>>>>>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>>>>>> index 5e99968939ce..077541fcba41 100644
>>>>>>> --- a/net/bluetooth/hci_event.c
>>>>>>> +++ b/net/bluetooth/hci_event.c
>>>>>>> @@ -42,6 +42,30 @@
>>>>>>>
>>>>>>> /* Handle HCI Event packets */
>>>>>>>
>>>>>>> +static void *hci_skb_pull(struct sk_buff *skb, size_t len)
>>>>>>> +{
>>>>>>> + void *data = skb->data;
>>>>>>> +
>>>>>>> + if (skb->len < len)
>>>>>>> + return NULL;
>>>>>>> +
>>>>>>> + skb_pull(skb, len);
>>>>>>> +
>>>>>>> + return data;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
>>>>>>> + u8 ev, size_t len)
>>>>>>> +{
>>>>>>> + void *data;
>>>>>>> +
>>>>>>> + data = hci_skb_pull(skb, len);
>>>>>>> + if (!data)
>>>>>>> + bt_dev_err(hdev, "Malformed Event: 0x%2.2x", ev);
>>>>>>> +
>>>>>>> + return data;
>>>>>>> +}
>>>>>>> +
>>>>>>
>>>>>> so if you do it in one function, this will look like this:
>>>>>>
>>>>>> static void *hci_ev_skb_pull(..)
>>>>>> {
>>>>>> void *data = skb->data;
>>>>>>
>>>>>> if (skb->len < len) {
>>>>>> bt_dev_err(hdev, “Malformed ..”);
>>>>>> return NULL;
>>>>>> }
>>>>>>
>>>>>> skb_pull(skb, len);
>>>>>> return data;
>>>>>> }
>>>>>>
>>>>>> static void *hci_cc_skb_pull(..)
>>>>>> {
>>>>>> void *data = skb->data;
>>>>>>
>>>>>> if (skb->len < len) {
>>>>>> bt_dev_err(..);
>>>>>> return NULL;
>>>>>> }
>>>>>>
>>>>>> skb_pull(..);
>>>>>> return data;
>>>>>> }
>>>>>>
>>>>>> I realize that you want to optimize the code with hci_skb_pull, but I don’t see how that makes it simpler or cleaner. In the end you just have spaghetti code and don’t win anything in size reduction or complexity.
>>>>>
>>>>> Right, I can either do that or perhaps bite the bullet and convert the
>>>>> whole hci_event.c to use a function table:
>>>>>
>>>>> #define HCI_EVENT(_op, _len, _func)...
>>>>>
>>>>> struct hci_event {
>>>>> __u8 op;
>>>>> __u16 len;
>>>>> func...
>>>>> } ev_table[] = {
>>>>> HCI_EVENT(...),
>>>>> }
>>>>>
>>>>> But that would pack a lot more changes since we would need to convert
>>>>> the whole switch to a for loop or alternatively if we don't want do a
>>>>> lookup we could omit the op and access the table by index if we want
>>>>> to trade speed over code size, with that we can have just one call to
>>>>> the likes of hci_ev_skb_pull.
>>>>
>>>> looping through a table is not ideal. There are too many events that you can receive and if we end up looping for every LE advertising report it would be rather silly. And of course a static table is possible since event numbers are assigned in order, but it also means some sort of overhead since we don’t parse each event.
>>>>
>>>> In addition to that dilemma, you have the problem that not all events are fixed size. So you end up indicating that similar to how we do it in btmon which will increase the table size again. Maybe that is actually ok since two giant switch statements also take time and code size.
>>>>
>>>> So our currently max event code is 0x57 for Authenticated Payload Timeout and the max LE event code is 0x3e for BIG Info Advertising Report. Meaning table one would have 87 entries and table would have two 63 entries. If we do min_len,max_len as uint8 then we have 2 octets and a function pointer. Maybe that is not too bad since that is all static const data.
>>>
>>> Yep, even if we have to have NOP for those event we don't handle I
>>> don't think it is such a big deal and accessing by index should be
>>> comparable in terms of speed to a switch statement, that said we may
>>> still need to do some checks on the callbacks for those events that
>>> have variable size I was only intending to do minimal size checks but
>>> perhaps you are saying it might be better to have a bool/flag saying
>>> that the event has variable size which matters when we are checking
>>> the length to either use == or <.
>>
>> I actually meant min_len + max_len.
>>
>> So you have for example
>>
>> HCI_EVENT(..) that sets min_len = x, max_len = x.
>> HCI_EVENT_VAR(..) that sets min_len = x and max_len = 253.
>>
>> No need for extra flags then.
>
> Ah got it, is there really a max_len for variable size though? Or you
> mean to say that should be limited to event buffer size? That Im
> afraid we only discover at runtime, anyway usually for variable size
> we should be using flex_array_size but that requires accessing the
> received skb so we can't really tell at build time and it will be
> likely left for the callback to figure out it has received enough data
> or not.

using max_len will make it flexible enough since in HCI event the max len is 253 as far as I recall. Or it was 255, but I don’t remember from the top of my head.

It also really doesn’t matter since if you need to change something, you just change the #define HCI_EVENT_VAR and that is it. I prefer to not make it more complicated than needed. The flex_array_size is nice, but I don’t know how much use that is in a static const structure array.

Regards

Marcel