Commit c9ed0a70 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann
Browse files

Bluetooth: Fix Set Extended (Scan Response) Data



These command do have variable length and the length can go up to 251,
so this changes the struct to not use a fixed size and then when
creating the PDU only the actual length of the data send to the
controller.

Fixes: a0fb3726 ("Bluetooth: Use Set ext adv/scan rsp data if controller supports")
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 3d4f9c00
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1775,13 +1775,15 @@ struct hci_cp_ext_adv_set {
	__u8  max_events;
} __packed;

#define HCI_MAX_EXT_AD_LENGTH	251

#define HCI_OP_LE_SET_EXT_ADV_DATA		0x2037
struct hci_cp_le_set_ext_adv_data {
	__u8  handle;
	__u8  operation;
	__u8  frag_pref;
	__u8  length;
	__u8  data[HCI_MAX_AD_LENGTH];
	__u8  data[];
} __packed;

#define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA		0x2038
@@ -1790,7 +1792,7 @@ struct hci_cp_le_set_ext_scan_rsp_data {
	__u8  operation;
	__u8  frag_pref;
	__u8  length;
	__u8  data[HCI_MAX_AD_LENGTH];
	__u8  data[];
} __packed;

#define LE_SET_ADV_DATA_OP_COMPLETE	0x03
+4 −4
Original line number Diff line number Diff line
@@ -228,9 +228,9 @@ struct adv_info {
	__u16	remaining_time;
	__u16	duration;
	__u16	adv_data_len;
	__u8	adv_data[HCI_MAX_AD_LENGTH];
	__u8	adv_data[HCI_MAX_EXT_AD_LENGTH];
	__u16	scan_rsp_len;
	__u8	scan_rsp_data[HCI_MAX_AD_LENGTH];
	__u8	scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
	__s8	tx_power;
	__u32   min_interval;
	__u32   max_interval;
@@ -551,9 +551,9 @@ struct hci_dev {
	DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);

	__s8			adv_tx_power;
	__u8			adv_data[HCI_MAX_AD_LENGTH];
	__u8			adv_data[HCI_MAX_EXT_AD_LENGTH];
	__u8			adv_data_len;
	__u8			scan_rsp_data[HCI_MAX_AD_LENGTH];
	__u8			scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
	__u8			scan_rsp_data_len;

	struct list_head	adv_instances;
+29 −22
Original line number Diff line number Diff line
@@ -1716,30 +1716,33 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
		return;

	if (ext_adv_capable(hdev)) {
		struct {
			struct hci_cp_le_set_ext_scan_rsp_data cp;
			u8 data[HCI_MAX_EXT_AD_LENGTH];
		} pdu;

		memset(&cp, 0, sizeof(cp));
		memset(&pdu, 0, sizeof(pdu));

		if (instance)
			len = create_instance_scan_rsp_data(hdev, instance,
							    cp.data);
							    pdu.data);
		else
			len = create_default_scan_rsp_data(hdev, cp.data);
			len = create_default_scan_rsp_data(hdev, pdu.data);

		if (hdev->scan_rsp_data_len == len &&
		    !memcmp(cp.data, hdev->scan_rsp_data, len))
		    !memcmp(pdu.data, hdev->scan_rsp_data, len))
			return;

		memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
		memcpy(hdev->scan_rsp_data, pdu.data, len);
		hdev->scan_rsp_data_len = len;

		cp.handle = instance;
		cp.length = len;
		cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
		cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
		pdu.cp.handle = instance;
		pdu.cp.length = len;
		pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
		pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;

		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, sizeof(cp),
			    &cp);
		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
			    sizeof(pdu.cp) + len, &pdu.cp);
	} else {
		struct hci_cp_le_set_scan_rsp_data cp;

@@ -1862,26 +1865,30 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
		return;

	if (ext_adv_capable(hdev)) {
		struct {
			struct hci_cp_le_set_ext_adv_data cp;
			u8 data[HCI_MAX_EXT_AD_LENGTH];
		} pdu;

		memset(&cp, 0, sizeof(cp));
		memset(&pdu, 0, sizeof(pdu));

		len = create_instance_adv_data(hdev, instance, cp.data);
		len = create_instance_adv_data(hdev, instance, pdu.data);

		/* There's nothing to do if the data hasn't changed */
		if (hdev->adv_data_len == len &&
		    memcmp(cp.data, hdev->adv_data, len) == 0)
		    memcmp(pdu.data, hdev->adv_data, len) == 0)
			return;

		memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
		memcpy(hdev->adv_data, pdu.data, len);
		hdev->adv_data_len = len;

		cp.length = len;
		cp.handle = instance;
		cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
		cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
		pdu.cp.length = len;
		pdu.cp.handle = instance;
		pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
		pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;

		hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(cp), &cp);
		hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA,
			    sizeof(pdu.cp) + len, &pdu.cp);
	} else {
		struct hci_cp_le_set_adv_data cp;