Skip to content

Commit 89fb8ac

Browse files
ceggers-arriVudentz
authored andcommitted
Bluetooth: HCI: Set extended advertising data synchronously
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]>
1 parent f3cb567 commit 89fb8ac

File tree

2 files changed

+130
-113
lines changed

2 files changed

+130
-113
lines changed

net/bluetooth/hci_event.c

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

2153-
static u8 hci_cc_set_ext_adv_param(struct hci_dev *hdev, void *data,
2154-
struct sk_buff *skb)
2155-
{
2156-
struct hci_rp_le_set_ext_adv_params *rp = data;
2157-
struct hci_cp_le_set_ext_adv_params *cp;
2158-
struct adv_info *adv_instance;
2159-
2160-
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
2161-
2162-
if (rp->status)
2163-
return rp->status;
2164-
2165-
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS);
2166-
if (!cp)
2167-
return rp->status;
2168-
2169-
hci_dev_lock(hdev);
2170-
hdev->adv_addr_type = cp->own_addr_type;
2171-
if (!cp->handle) {
2172-
/* Store in hdev for instance 0 */
2173-
hdev->adv_tx_power = rp->tx_power;
2174-
} else {
2175-
adv_instance = hci_find_adv_instance(hdev, cp->handle);
2176-
if (adv_instance)
2177-
adv_instance->tx_power = rp->tx_power;
2178-
}
2179-
/* Update adv data as tx power is known now */
2180-
hci_update_adv_data(hdev, cp->handle);
2181-
2182-
hci_dev_unlock(hdev);
2183-
2184-
return rp->status;
2185-
}
2186-
21872153
static u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data,
21882154
struct sk_buff *skb)
21892155
{
@@ -4164,8 +4130,6 @@ static const struct hci_cc {
41644130
HCI_CC(HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
41654131
hci_cc_le_read_num_adv_sets,
41664132
sizeof(struct hci_rp_le_read_num_supported_adv_sets)),
4167-
HCI_CC(HCI_OP_LE_SET_EXT_ADV_PARAMS, hci_cc_set_ext_adv_param,
4168-
sizeof(struct hci_rp_le_set_ext_adv_params)),
41694133
HCI_CC_STATUS(HCI_OP_LE_SET_EXT_ADV_ENABLE,
41704134
hci_cc_le_set_ext_adv_enable),
41714135
HCI_CC_STATUS(HCI_OP_LE_SET_ADV_SET_RAND_ADDR,

net/bluetooth/hci_sync.c

Lines changed: 130 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,9 +1205,126 @@ static int hci_set_adv_set_random_addr_sync(struct hci_dev *hdev, u8 instance,
12051205
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
12061206
}
12071207

1208+
static int
1209+
hci_set_ext_adv_params_sync(struct hci_dev *hdev, struct adv_info *adv,
1210+
const struct hci_cp_le_set_ext_adv_params *cp,
1211+
struct hci_rp_le_set_ext_adv_params *rp)
1212+
{
1213+
struct sk_buff *skb;
1214+
1215+
skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
1216+
cp, HCI_CMD_TIMEOUT);
1217+
1218+
/* If command return a status event, skb will be set to -ENODATA */
1219+
if (skb == ERR_PTR(-ENODATA))
1220+
return 0;
1221+
1222+
if (IS_ERR(skb)) {
1223+
bt_dev_err(hdev, "Opcode 0x%4.4x failed: %ld",
1224+
HCI_OP_LE_SET_EXT_ADV_PARAMS, PTR_ERR(skb));
1225+
return PTR_ERR(skb);
1226+
}
1227+
1228+
if (skb->len != sizeof(*rp)) {
1229+
bt_dev_err(hdev, "Invalid response length for 0x%4.4x: %u",
1230+
HCI_OP_LE_SET_EXT_ADV_PARAMS, skb->len);
1231+
kfree_skb(skb);
1232+
return -EIO;
1233+
}
1234+
1235+
memcpy(rp, skb->data, sizeof(*rp));
1236+
kfree_skb(skb);
1237+
1238+
if (!rp->status) {
1239+
hdev->adv_addr_type = cp->own_addr_type;
1240+
if (!cp->handle) {
1241+
/* Store in hdev for instance 0 */
1242+
hdev->adv_tx_power = rp->tx_power;
1243+
} else if (adv) {
1244+
adv->tx_power = rp->tx_power;
1245+
}
1246+
}
1247+
1248+
return rp->status;
1249+
}
1250+
1251+
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
1252+
{
1253+
DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
1254+
HCI_MAX_EXT_AD_LENGTH);
1255+
u8 len;
1256+
struct adv_info *adv = NULL;
1257+
int err;
1258+
1259+
if (instance) {
1260+
adv = hci_find_adv_instance(hdev, instance);
1261+
if (!adv || !adv->adv_data_changed)
1262+
return 0;
1263+
}
1264+
1265+
len = eir_create_adv_data(hdev, instance, pdu->data,
1266+
HCI_MAX_EXT_AD_LENGTH);
1267+
1268+
pdu->length = len;
1269+
pdu->handle = adv ? adv->handle : instance;
1270+
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1271+
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1272+
1273+
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
1274+
struct_size(pdu, data, len), pdu,
1275+
HCI_CMD_TIMEOUT);
1276+
if (err)
1277+
return err;
1278+
1279+
/* Update data if the command succeed */
1280+
if (adv) {
1281+
adv->adv_data_changed = false;
1282+
} else {
1283+
memcpy(hdev->adv_data, pdu->data, len);
1284+
hdev->adv_data_len = len;
1285+
}
1286+
1287+
return 0;
1288+
}
1289+
1290+
static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
1291+
{
1292+
struct hci_cp_le_set_adv_data cp;
1293+
u8 len;
1294+
1295+
memset(&cp, 0, sizeof(cp));
1296+
1297+
len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));
1298+
1299+
/* There's nothing to do if the data hasn't changed */
1300+
if (hdev->adv_data_len == len &&
1301+
memcmp(cp.data, hdev->adv_data, len) == 0)
1302+
return 0;
1303+
1304+
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1305+
hdev->adv_data_len = len;
1306+
1307+
cp.length = len;
1308+
1309+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
1310+
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1311+
}
1312+
1313+
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
1314+
{
1315+
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1316+
return 0;
1317+
1318+
if (ext_adv_capable(hdev))
1319+
return hci_set_ext_adv_data_sync(hdev, instance);
1320+
1321+
return hci_set_adv_data_sync(hdev, instance);
1322+
}
1323+
12081324
int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
12091325
{
12101326
struct hci_cp_le_set_ext_adv_params cp;
1327+
struct hci_rp_le_set_ext_adv_params rp;
12111328
bool connectable;
12121329
u32 flags;
12131330
bdaddr_t random_addr;
@@ -1316,8 +1433,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
13161433
cp.secondary_phy = HCI_ADV_PHY_1M;
13171434
}
13181435

1319-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
1320-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1436+
err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp);
1437+
if (err)
1438+
return err;
1439+
1440+
/* Update adv data as tx power is known now */
1441+
err = hci_set_ext_adv_data_sync(hdev, cp.handle);
13211442
if (err)
13221443
return err;
13231444

@@ -1822,79 +1943,6 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason)
18221943
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
18231944
}
18241945

1825-
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
1826-
{
1827-
DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
1828-
HCI_MAX_EXT_AD_LENGTH);
1829-
u8 len;
1830-
struct adv_info *adv = NULL;
1831-
int err;
1832-
1833-
if (instance) {
1834-
adv = hci_find_adv_instance(hdev, instance);
1835-
if (!adv || !adv->adv_data_changed)
1836-
return 0;
1837-
}
1838-
1839-
len = eir_create_adv_data(hdev, instance, pdu->data,
1840-
HCI_MAX_EXT_AD_LENGTH);
1841-
1842-
pdu->length = len;
1843-
pdu->handle = adv ? adv->handle : instance;
1844-
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1845-
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1846-
1847-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
1848-
struct_size(pdu, data, len), pdu,
1849-
HCI_CMD_TIMEOUT);
1850-
if (err)
1851-
return err;
1852-
1853-
/* Update data if the command succeed */
1854-
if (adv) {
1855-
adv->adv_data_changed = false;
1856-
} else {
1857-
memcpy(hdev->adv_data, pdu->data, len);
1858-
hdev->adv_data_len = len;
1859-
}
1860-
1861-
return 0;
1862-
}
1863-
1864-
static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
1865-
{
1866-
struct hci_cp_le_set_adv_data cp;
1867-
u8 len;
1868-
1869-
memset(&cp, 0, sizeof(cp));
1870-
1871-
len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));
1872-
1873-
/* There's nothing to do if the data hasn't changed */
1874-
if (hdev->adv_data_len == len &&
1875-
memcmp(cp.data, hdev->adv_data, len) == 0)
1876-
return 0;
1877-
1878-
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1879-
hdev->adv_data_len = len;
1880-
1881-
cp.length = len;
1882-
1883-
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
1884-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
1885-
}
1886-
1887-
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
1888-
{
1889-
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1890-
return 0;
1891-
1892-
if (ext_adv_capable(hdev))
1893-
return hci_set_ext_adv_data_sync(hdev, instance);
1894-
1895-
return hci_set_adv_data_sync(hdev, instance);
1896-
}
1897-
18981946
int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
18991947
bool force)
19001948
{
@@ -6273,6 +6321,7 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
62736321
struct hci_conn *conn)
62746322
{
62756323
struct hci_cp_le_set_ext_adv_params cp;
6324+
struct hci_rp_le_set_ext_adv_params rp;
62766325
int err;
62776326
bdaddr_t random_addr;
62786327
u8 own_addr_type;
@@ -6314,8 +6363,12 @@ static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
63146363
if (err)
63156364
return err;
63166365

6317-
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
6318-
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
6366+
err = hci_set_ext_adv_params_sync(hdev, NULL, &cp, &rp);
6367+
if (err)
6368+
return err;
6369+
6370+
/* Update adv data as tx power is known now */
6371+
err = hci_set_ext_adv_data_sync(hdev, cp.handle);
63196372
if (err)
63206373
return err;
63216374

0 commit comments

Comments
 (0)