mirror of
https://github.com/torvalds/linux.git
synced 2024-10-24 22:20:55 +00:00
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: a0fb3726ba
("Bluetooth: Use Set ext adv/scan rsp data if controller supports")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
3d4f9c0049
commit
c9ed0a7077
|
@ -1775,13 +1775,15 @@ struct hci_cp_ext_adv_set {
|
||||||
__u8 max_events;
|
__u8 max_events;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_MAX_EXT_AD_LENGTH 251
|
||||||
|
|
||||||
#define HCI_OP_LE_SET_EXT_ADV_DATA 0x2037
|
#define HCI_OP_LE_SET_EXT_ADV_DATA 0x2037
|
||||||
struct hci_cp_le_set_ext_adv_data {
|
struct hci_cp_le_set_ext_adv_data {
|
||||||
__u8 handle;
|
__u8 handle;
|
||||||
__u8 operation;
|
__u8 operation;
|
||||||
__u8 frag_pref;
|
__u8 frag_pref;
|
||||||
__u8 length;
|
__u8 length;
|
||||||
__u8 data[HCI_MAX_AD_LENGTH];
|
__u8 data[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038
|
#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 operation;
|
||||||
__u8 frag_pref;
|
__u8 frag_pref;
|
||||||
__u8 length;
|
__u8 length;
|
||||||
__u8 data[HCI_MAX_AD_LENGTH];
|
__u8 data[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define LE_SET_ADV_DATA_OP_COMPLETE 0x03
|
#define LE_SET_ADV_DATA_OP_COMPLETE 0x03
|
||||||
|
|
|
@ -228,9 +228,9 @@ struct adv_info {
|
||||||
__u16 remaining_time;
|
__u16 remaining_time;
|
||||||
__u16 duration;
|
__u16 duration;
|
||||||
__u16 adv_data_len;
|
__u16 adv_data_len;
|
||||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
|
||||||
__u16 scan_rsp_len;
|
__u16 scan_rsp_len;
|
||||||
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
|
__u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
|
||||||
__s8 tx_power;
|
__s8 tx_power;
|
||||||
__u32 min_interval;
|
__u32 min_interval;
|
||||||
__u32 max_interval;
|
__u32 max_interval;
|
||||||
|
@ -551,9 +551,9 @@ struct hci_dev {
|
||||||
DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
|
DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
|
||||||
|
|
||||||
__s8 adv_tx_power;
|
__s8 adv_tx_power;
|
||||||
__u8 adv_data[HCI_MAX_AD_LENGTH];
|
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
|
||||||
__u8 adv_data_len;
|
__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;
|
__u8 scan_rsp_data_len;
|
||||||
|
|
||||||
struct list_head adv_instances;
|
struct list_head adv_instances;
|
||||||
|
|
|
@ -1716,30 +1716,33 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ext_adv_capable(hdev)) {
|
if (ext_adv_capable(hdev)) {
|
||||||
struct hci_cp_le_set_ext_scan_rsp_data cp;
|
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)
|
if (instance)
|
||||||
len = create_instance_scan_rsp_data(hdev, instance,
|
len = create_instance_scan_rsp_data(hdev, instance,
|
||||||
cp.data);
|
pdu.data);
|
||||||
else
|
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 &&
|
if (hdev->scan_rsp_data_len == len &&
|
||||||
!memcmp(cp.data, hdev->scan_rsp_data, len))
|
!memcmp(pdu.data, hdev->scan_rsp_data, len))
|
||||||
return;
|
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;
|
hdev->scan_rsp_data_len = len;
|
||||||
|
|
||||||
cp.handle = instance;
|
pdu.cp.handle = instance;
|
||||||
cp.length = len;
|
pdu.cp.length = len;
|
||||||
cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
|
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
|
||||||
cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
|
pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
|
||||||
|
|
||||||
hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, sizeof(cp),
|
hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
|
||||||
&cp);
|
sizeof(pdu.cp) + len, &pdu.cp);
|
||||||
} else {
|
} else {
|
||||||
struct hci_cp_le_set_scan_rsp_data cp;
|
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;
|
return;
|
||||||
|
|
||||||
if (ext_adv_capable(hdev)) {
|
if (ext_adv_capable(hdev)) {
|
||||||
struct hci_cp_le_set_ext_adv_data cp;
|
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 */
|
/* There's nothing to do if the data hasn't changed */
|
||||||
if (hdev->adv_data_len == len &&
|
if (hdev->adv_data_len == len &&
|
||||||
memcmp(cp.data, hdev->adv_data, len) == 0)
|
memcmp(pdu.data, hdev->adv_data, len) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
|
memcpy(hdev->adv_data, pdu.data, len);
|
||||||
hdev->adv_data_len = len;
|
hdev->adv_data_len = len;
|
||||||
|
|
||||||
cp.length = len;
|
pdu.cp.length = len;
|
||||||
cp.handle = instance;
|
pdu.cp.handle = instance;
|
||||||
cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
|
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
|
||||||
cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
|
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 {
|
} else {
|
||||||
struct hci_cp_le_set_adv_data cp;
|
struct hci_cp_le_set_adv_data cp;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user