Skip to content

Commit 0e8776b

Browse files
ceggers-arrigregkh
authored andcommitted
Bluetooth: HCI: Set extended advertising data synchronously
commit 89fb8acc38852116d38d721ad394aad7f2871670 upstream. Currently, for controllers with extended advertising, the advertising data is set in the asynchronous response handler for extended adverstising params. As most advertising settings are performed in a synchronous context, the (asynchronous) setting of the advertising data is done too late (after enabling the advertising). Move setting of adverstising data from asynchronous response handler into synchronous context to fix ordering of HCI commands. Signed-off-by: Christian Eggers <[email protected]> Fixes: a0fb372 ("Bluetooth: Use Set ext adv/scan rsp data if controller supports") Cc: [email protected] v2: https://lore.kernel.org/linux-bluetooth/[email protected]/ Signed-off-by: Luiz Augusto von Dentz <[email protected]> [ Adapted DEFINE_FLEX macro usage to struct with flexible array member for compatibility with kernel 6.1. ] Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 15e07dd commit 0e8776b

File tree

2 files changed

+133
-116
lines changed

2 files changed

+133
-116
lines changed

net/bluetooth/hci_event.c

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,40 +2196,6 @@ static u8 hci_cc_set_adv_param(struct hci_dev *hdev, void *data,
21962196
return rp->status;
21972197
}
21982198

2199-
static u8 hci_cc_set_ext_adv_param(struct hci_dev *hdev, void *data,
2200-
struct sk_buff *skb)
2201-
{
2202-
struct hci_rp_le_set_ext_adv_params *rp = data;
2203-
struct hci_cp_le_set_ext_adv_params *cp;
2204-
struct adv_info *adv_instance;
2205-
2206-
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
2207-
2208-
if (rp->status)
2209-
return rp->status;
2210-
2211-
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS);
2212-
if (!cp)
2213-
return rp->status;
2214-
2215-
hci_dev_lock(hdev);
2216-
hdev->adv_addr_type = cp->own_addr_type;
2217-
if (!cp->handle) {
2218-
/* Store in hdev for instance 0 */
2219-
hdev->adv_tx_power = rp->tx_power;
2220-
} else {
2221-
adv_instance = hci_find_adv_instance(hdev, cp->handle);
2222-
if (adv_instance)
2223-
adv_instance->tx_power = rp->tx_power;
2224-
}
2225-
/* Update adv data as tx power is known now */
2226-
hci_update_adv_data(hdev, cp->handle);
2227-
2228-
hci_dev_unlock(hdev);
2229-
2230-
return rp->status;
2231-
}
2232-
22332199
static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data,
22342200
struct sk_buff *skb)
22352201
{
@@ -4172,8 +4138,6 @@ static const struct hci_cc {
41724138
HCI_CC(HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
41734139
hci_cc_le_read_num_adv_sets,
41744140
sizeof(struct hci_rp_le_read_num_supported_adv_sets)),
4175-
HCI_CC(HCI_OP_LE_SET_EXT_ADV_PARAMS, hci_cc_set_ext_adv_param,
4176-
sizeof(struct hci_rp_le_set_ext_adv_params)),
41774141
HCI_CC_STATUS(HCI_OP_LE_SET_EXT_ADV_ENABLE,
41784142
hci_cc_le_set_ext_adv_enable),
41794143
HCI_CC_STATUS(HCI_OP_LE_SET_ADV_SET_RAND_ADDR,

net/bluetooth/hci_sync.c

Lines changed: 133 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,9 +1181,129 @@ static int hci_set_adv_set_random_addr_sync(struct hci_dev *hdev, u8 instance,
11811181
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
11821182
}
11831183

1184+
static int
1185+
hci_set_ext_adv_params_sync(struct hci_dev *hdev, struct adv_info *adv,
1186+
const struct hci_cp_le_set_ext_adv_params *cp,
1187+
struct hci_rp_le_set_ext_adv_params *rp)
1188+
{
1189+
struct sk_buff *skb;
1190+
1191+
skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
1192+
cp, HCI_CMD_TIMEOUT);
1193+
1194+
/* If command return a status event, skb will be set to -ENODATA */
1195+
if (skb == ERR_PTR(-ENODATA))
1196+
return 0;
1197+
1198+
if (IS_ERR(skb)) {
1199+
bt_dev_err(hdev, "Opcode 0x%4.4x failed: %ld",
1200+
HCI_OP_LE_SET_EXT_ADV_PARAMS, PTR_ERR(skb));
1201+
return PTR_ERR(skb);
1202+
}
1203+
1204+
if (skb->len != sizeof(*rp)) {
1205+
bt_dev_err(hdev, "Invalid response length for 0x%4.4x: %u",
1206+
HCI_OP_LE_SET_EXT_ADV_PARAMS, skb->len);
1207+
kfree_skb(skb);
1208+
return -EIO;
1209+
}
1210+
1211+
memcpy(rp, skb->data, sizeof(*rp));
1212+
kfree_skb(skb);
1213+
1214+
if (!rp->status) {
1215+
hdev->adv_addr_type = cp->own_addr_type;
1216+
if (!cp->handle) {
1217+
/* Store in hdev for instance 0 */
1218+
hdev->adv_tx_power = rp->tx_power;
1219+
} else if (adv) {
1220+
adv->tx_power = rp->tx_power;
1221+
}
1222+
}
1223+
1224+
return rp->status;
1225+
}
1226+
1227+
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
1228+
{
1229+
struct {
1230+
struct hci_cp_le_set_ext_adv_data cp;
1231+
u8 data[HCI_MAX_EXT_AD_LENGTH];
1232+
} pdu;
1233+
u8 len;
1234+
struct adv_info *adv = NULL;
1235+
int err;
1236+
1237+
memset(&pdu, 0, sizeof(pdu));
1238+
1239+
if (instance) {
1240+
adv = hci_find_adv_instance(hdev, instance);
1241+
if (!adv || !adv->adv_data_changed)
1242+
return 0;
1243+
}
1244+
1245+
len = eir_create_adv_data(hdev, instance, pdu.data);
1246+
1247+
pdu.cp.length = len;
1248+
pdu.cp.handle = instance;
1249+
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1250+
pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1251+
1252+
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
1253+
sizeof(pdu.cp) + len, &pdu.cp,
1254+
HCI_CMD_TIMEOUT);
1255+
if (err)
1256+
return err;
1257+
1258+
/* Update data if the command succeed */
1259+
if (adv) {
1260+
adv->adv_data_changed = false;
1261+
} else {
1262+
memcpy(hdev->adv_data, pdu.data, len);
1263+
hdev->adv_data_len = len;
1264+
}
1265+
1266+
return 0;
1267+
}
1268+
1269+
static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
1270+
{
1271+
struct hci_cp_le_set_adv_data cp;
1272+
u8 len;
1273+
1274+
memset(&cp, 0, sizeof(cp));
1275+
1276+
len = eir_create_adv_data(hdev, instance, cp.data);
1277+
1278+
/* There's nothing to do if the data hasn't changed */
1279+
if (hdev->adv_data_len == len &&
1280+
memcmp(cp.data, hdev->adv_data, len) == 0)
1281+
return 0;
1282+
1283+
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1284+
hdev->adv_data_len = len;
1285+
1286+
cp.length = len;
1287+
1288+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
1289+
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1290+
}
1291+
1292+
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
1293+
{
1294+
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1295+
return 0;
1296+
1297+
if (ext_adv_capable(hdev))
1298+
return hci_set_ext_adv_data_sync(hdev, instance);
1299+
1300+
return hci_set_adv_data_sync(hdev, instance);
1301+
}
1302+
11841303
int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
11851304
{
11861305
struct hci_cp_le_set_ext_adv_params cp;
1306+
struct hci_rp_le_set_ext_adv_params rp;
11871307
bool connectable;
11881308
u32 flags;
11891309
bdaddr_t random_addr;
@@ -1290,8 +1410,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
12901410
cp.secondary_phy = HCI_ADV_PHY_1M;
12911411
}
12921412

1293-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
1294-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1413+
err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp);
1414+
if (err)
1415+
return err;
1416+
1417+
/* Update adv data as tx power is known now */
1418+
err = hci_set_ext_adv_data_sync(hdev, cp.handle);
12951419
if (err)
12961420
return err;
12971421

@@ -1815,82 +1939,6 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason)
18151939
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
18161940
}
18171941

1818-
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
1819-
{
1820-
struct {
1821-
struct hci_cp_le_set_ext_adv_data cp;
1822-
u8 data[HCI_MAX_EXT_AD_LENGTH];
1823-
} pdu;
1824-
u8 len;
1825-
struct adv_info *adv = NULL;
1826-
int err;
1827-
1828-
memset(&pdu, 0, sizeof(pdu));
1829-
1830-
if (instance) {
1831-
adv = hci_find_adv_instance(hdev, instance);
1832-
if (!adv || !adv->adv_data_changed)
1833-
return 0;
1834-
}
1835-
1836-
len = eir_create_adv_data(hdev, instance, pdu.data);
1837-
1838-
pdu.cp.length = len;
1839-
pdu.cp.handle = instance;
1840-
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1841-
pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1842-
1843-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
1844-
sizeof(pdu.cp) + len, &pdu.cp,
1845-
HCI_CMD_TIMEOUT);
1846-
if (err)
1847-
return err;
1848-
1849-
/* Update data if the command succeed */
1850-
if (adv) {
1851-
adv->adv_data_changed = false;
1852-
} else {
1853-
memcpy(hdev->adv_data, pdu.data, len);
1854-
hdev->adv_data_len = len;
1855-
}
1856-
1857-
return 0;
1858-
}
1859-
1860-
static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
1861-
{
1862-
struct hci_cp_le_set_adv_data cp;
1863-
u8 len;
1864-
1865-
memset(&cp, 0, sizeof(cp));
1866-
1867-
len = eir_create_adv_data(hdev, instance, cp.data);
1868-
1869-
/* There's nothing to do if the data hasn't changed */
1870-
if (hdev->adv_data_len == len &&
1871-
memcmp(cp.data, hdev->adv_data, len) == 0)
1872-
return 0;
1873-
1874-
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1875-
hdev->adv_data_len = len;
1876-
1877-
cp.length = len;
1878-
1879-
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
1880-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1881-
}
1882-
1883-
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
1884-
{
1885-
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1886-
return 0;
1887-
1888-
if (ext_adv_capable(hdev))
1889-
return hci_set_ext_adv_data_sync(hdev, instance);
1890-
1891-
return hci_set_adv_data_sync(hdev, instance);
1892-
}
1893-
18941942
int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
18951943
bool force)
18961944
{
@@ -6127,6 +6175,7 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
61276175
struct hci_conn *conn)
61286176
{
61296177
struct hci_cp_le_set_ext_adv_params cp;
6178+
struct hci_rp_le_set_ext_adv_params rp;
61306179
int err;
61316180
bdaddr_t random_addr;
61326181
u8 own_addr_type;
@@ -6169,8 +6218,12 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
61696218
if (err)
61706219
return err;
61716220

6172-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
6173-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
6221+
err = hci_set_ext_adv_params_sync(hdev, NULL, &cp, &rp);
6222+
if (err)
6223+
return err;
6224+
6225+
/* Update adv data as tx power is known now */
6226+
err = hci_set_ext_adv_data_sync(hdev, cp.handle);
61746227
if (err)
61756228
return err;
61766229

0 commit comments

Comments
 (0)