Merge tag 'for-net-2025-06-11' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - eir: Fix NULL pointer deference on eir_get_service_data - eir: Fix possible crashes on eir_create_adv_data - hci_sync: Fix broadcast/PA when using an existing instance - ISO: Fix using BT_SK_PA_SYNC to detect BIS sockets - ISO: Fix not using bc_sid as advertisement SID - MGMT: Fix sparse errors * tag 'for-net-2025-06-11' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: MGMT: Fix sparse errors Bluetooth: ISO: Fix not using bc_sid as advertisement SID Bluetooth: ISO: Fix using BT_SK_PA_SYNC to detect BIS sockets Bluetooth: eir: Fix possible crashes on eir_create_adv_data Bluetooth: hci_sync: Fix broadcast/PA when using an existing instance Bluetooth: Fix NULL pointer deference on eir_get_service_data ==================== Link: https://patch.msgid.link/20250611204944.1559356-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -242,6 +242,7 @@ struct adv_info {
|
||||
__u8 mesh;
|
||||
__u8 instance;
|
||||
__u8 handle;
|
||||
__u8 sid;
|
||||
__u32 flags;
|
||||
__u16 timeout;
|
||||
__u16 remaining_time;
|
||||
@@ -1551,13 +1552,14 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u16 timeout);
|
||||
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, struct bt_iso_qos *qos);
|
||||
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
||||
struct bt_iso_qos *qos,
|
||||
__u8 base_len, __u8 *base);
|
||||
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, struct bt_iso_qos *qos);
|
||||
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, struct bt_iso_qos *qos,
|
||||
__u8 dst_type, __u8 sid,
|
||||
struct bt_iso_qos *qos,
|
||||
__u8 data_len, __u8 *data);
|
||||
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, __u8 sid, struct bt_iso_qos *qos);
|
||||
@@ -1832,6 +1834,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
|
||||
void hci_adv_instances_clear(struct hci_dev *hdev);
|
||||
struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
|
||||
struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid);
|
||||
struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance);
|
||||
struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
|
||||
u32 flags, u16 adv_data_len, u8 *adv_data,
|
||||
@@ -1839,7 +1842,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
|
||||
u16 timeout, u16 duration, s8 tx_power,
|
||||
u32 min_interval, u32 max_interval,
|
||||
u8 mesh_handle);
|
||||
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
|
||||
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid,
|
||||
u32 flags, u8 data_len, u8 *data,
|
||||
u32 min_interval, u32 max_interval);
|
||||
int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance,
|
||||
|
||||
@@ -115,8 +115,8 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance);
|
||||
int hci_enable_advertising_sync(struct hci_dev *hdev);
|
||||
int hci_enable_advertising(struct hci_dev *hdev);
|
||||
|
||||
int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
|
||||
u8 *data, u32 flags, u16 min_interval,
|
||||
int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid,
|
||||
u8 data_len, u8 *data, u32 flags, u16 min_interval,
|
||||
u16 max_interval, u16 sync_interval);
|
||||
|
||||
int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance);
|
||||
|
||||
+10
-7
@@ -242,7 +242,7 @@ u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
return ad_len;
|
||||
}
|
||||
|
||||
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
|
||||
{
|
||||
struct adv_info *adv = NULL;
|
||||
u8 ad_len = 0, flags = 0;
|
||||
@@ -286,7 +286,7 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
/* If flags would still be empty, then there is no need to
|
||||
* include the "Flags" AD field".
|
||||
*/
|
||||
if (flags) {
|
||||
if (flags && (ad_len + eir_precalc_len(1) <= size)) {
|
||||
ptr[0] = 0x02;
|
||||
ptr[1] = EIR_FLAGS;
|
||||
ptr[2] = flags;
|
||||
@@ -316,7 +316,8 @@ skip_flags:
|
||||
}
|
||||
|
||||
/* Provide Tx Power only if we can provide a valid value for it */
|
||||
if (adv_tx_power != HCI_TX_POWER_INVALID) {
|
||||
if (adv_tx_power != HCI_TX_POWER_INVALID &&
|
||||
(ad_len + eir_precalc_len(1) <= size)) {
|
||||
ptr[0] = 0x02;
|
||||
ptr[1] = EIR_TX_POWER;
|
||||
ptr[2] = (u8)adv_tx_power;
|
||||
@@ -366,17 +367,19 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
|
||||
void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
|
||||
{
|
||||
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, len))) {
|
||||
size_t dlen;
|
||||
|
||||
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) {
|
||||
u16 value = get_unaligned_le16(eir);
|
||||
|
||||
if (uuid == value) {
|
||||
if (len)
|
||||
*len -= 2;
|
||||
*len = dlen - 2;
|
||||
return &eir[2];
|
||||
}
|
||||
|
||||
eir += *len;
|
||||
eir_len -= *len;
|
||||
eir += dlen;
|
||||
eir_len -= dlen;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
void eir_create(struct hci_dev *hdev, u8 *data);
|
||||
|
||||
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);
|
||||
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
|
||||
u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
|
||||
u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);
|
||||
|
||||
|
||||
@@ -1501,8 +1501,8 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos)
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
struct bt_iso_qos *qos, __u8 base_len,
|
||||
__u8 *base)
|
||||
__u8 sid, struct bt_iso_qos *qos,
|
||||
__u8 base_len, __u8 *base)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
int err;
|
||||
@@ -1543,6 +1543,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
return conn;
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->sid = sid;
|
||||
|
||||
hci_conn_hold(conn);
|
||||
return conn;
|
||||
@@ -2062,7 +2063,8 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
|
||||
if (qos->bcast.bis)
|
||||
sync_interval = interval * 4;
|
||||
|
||||
err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->le_per_adv_data_len,
|
||||
err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->sid,
|
||||
conn->le_per_adv_data_len,
|
||||
conn->le_per_adv_data, flags, interval,
|
||||
interval, sync_interval);
|
||||
if (err)
|
||||
@@ -2134,7 +2136,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
|
||||
}
|
||||
}
|
||||
|
||||
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
||||
struct bt_iso_qos *qos,
|
||||
__u8 base_len, __u8 *base)
|
||||
{
|
||||
@@ -2156,7 +2158,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
base, base_len);
|
||||
|
||||
/* We need hci_conn object using the BDADDR_ANY as dst */
|
||||
conn = hci_add_bis(hdev, dst, qos, base_len, eir);
|
||||
conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
@@ -2207,20 +2209,35 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data)
|
||||
}
|
||||
|
||||
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, struct bt_iso_qos *qos,
|
||||
__u8 dst_type, __u8 sid,
|
||||
struct bt_iso_qos *qos,
|
||||
__u8 base_len, __u8 *base)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
int err;
|
||||
struct iso_list_data data;
|
||||
|
||||
conn = hci_bind_bis(hdev, dst, qos, base_len, base);
|
||||
conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
if (conn->state == BT_CONNECTED)
|
||||
return conn;
|
||||
|
||||
/* Check if SID needs to be allocated then search for the first
|
||||
* available.
|
||||
*/
|
||||
if (conn->sid == HCI_SID_INVALID) {
|
||||
u8 sid;
|
||||
|
||||
for (sid = 0; sid <= 0x0f; sid++) {
|
||||
if (!hci_find_adv_sid(hdev, sid)) {
|
||||
conn->sid = sid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.big = qos->bcast.big;
|
||||
data.bis = qos->bcast.bis;
|
||||
|
||||
|
||||
@@ -1584,6 +1584,19 @@ struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
struct adv_info *hci_find_adv_sid(struct hci_dev *hdev, u8 sid)
|
||||
{
|
||||
struct adv_info *adv;
|
||||
|
||||
list_for_each_entry(adv, &hdev->adv_instances, list) {
|
||||
if (adv->sid == sid)
|
||||
return adv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance)
|
||||
{
|
||||
@@ -1736,7 +1749,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
|
||||
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, u8 sid,
|
||||
u32 flags, u8 data_len, u8 *data,
|
||||
u32 min_interval, u32 max_interval)
|
||||
{
|
||||
@@ -1748,6 +1761,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
|
||||
if (IS_ERR(adv))
|
||||
return adv;
|
||||
|
||||
adv->sid = sid;
|
||||
adv->periodic = true;
|
||||
adv->per_adv_data_len = data_len;
|
||||
|
||||
|
||||
+35
-10
@@ -1261,10 +1261,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
|
||||
hci_cpu_to_le24(adv->min_interval, cp.min_interval);
|
||||
hci_cpu_to_le24(adv->max_interval, cp.max_interval);
|
||||
cp.tx_power = adv->tx_power;
|
||||
cp.sid = adv->sid;
|
||||
} else {
|
||||
hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval);
|
||||
hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval);
|
||||
cp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
|
||||
cp.sid = 0x00;
|
||||
}
|
||||
|
||||
secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK);
|
||||
@@ -1559,7 +1561,8 @@ static int hci_enable_per_advertising_sync(struct hci_dev *hdev, u8 instance)
|
||||
static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv)
|
||||
{
|
||||
u8 bid[3];
|
||||
u8 ad[4 + 3];
|
||||
u8 ad[HCI_MAX_EXT_AD_LENGTH];
|
||||
u8 len;
|
||||
|
||||
/* Skip if NULL adv as instance 0x00 is used for general purpose
|
||||
* advertising so it cannot used for the likes of Broadcast Announcement
|
||||
@@ -1585,14 +1588,16 @@ static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv)
|
||||
|
||||
/* Generate Broadcast ID */
|
||||
get_random_bytes(bid, sizeof(bid));
|
||||
eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid));
|
||||
hci_set_adv_instance_data(hdev, adv->instance, sizeof(ad), ad, 0, NULL);
|
||||
len = eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid));
|
||||
memcpy(ad + len, adv->adv_data, adv->adv_data_len);
|
||||
hci_set_adv_instance_data(hdev, adv->instance, len + adv->adv_data_len,
|
||||
ad, 0, NULL);
|
||||
|
||||
return hci_update_adv_data_sync(hdev, adv->instance);
|
||||
}
|
||||
|
||||
int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
|
||||
u8 *data, u32 flags, u16 min_interval,
|
||||
int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 sid,
|
||||
u8 data_len, u8 *data, u32 flags, u16 min_interval,
|
||||
u16 max_interval, u16 sync_interval)
|
||||
{
|
||||
struct adv_info *adv = NULL;
|
||||
@@ -1603,9 +1608,28 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
|
||||
|
||||
if (instance) {
|
||||
adv = hci_find_adv_instance(hdev, instance);
|
||||
/* Create an instance if that could not be found */
|
||||
if (!adv) {
|
||||
adv = hci_add_per_instance(hdev, instance, flags,
|
||||
if (adv) {
|
||||
if (sid != HCI_SID_INVALID && adv->sid != sid) {
|
||||
/* If the SID don't match attempt to find by
|
||||
* SID.
|
||||
*/
|
||||
adv = hci_find_adv_sid(hdev, sid);
|
||||
if (!adv) {
|
||||
bt_dev_err(hdev,
|
||||
"Unable to find adv_info");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn it into periodic advertising */
|
||||
adv->periodic = true;
|
||||
adv->per_adv_data_len = data_len;
|
||||
if (data)
|
||||
memcpy(adv->per_adv_data, data, data_len);
|
||||
adv->flags = flags;
|
||||
} else if (!adv) {
|
||||
/* Create an instance if that could not be found */
|
||||
adv = hci_add_per_instance(hdev, instance, sid, flags,
|
||||
data_len, data,
|
||||
sync_interval,
|
||||
sync_interval);
|
||||
@@ -1812,7 +1836,8 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = eir_create_adv_data(hdev, instance, pdu->data);
|
||||
len = eir_create_adv_data(hdev, instance, pdu->data,
|
||||
HCI_MAX_EXT_AD_LENGTH);
|
||||
|
||||
pdu->length = len;
|
||||
pdu->handle = adv ? adv->handle : instance;
|
||||
@@ -1843,7 +1868,7 @@ static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
len = eir_create_adv_data(hdev, instance, cp.data);
|
||||
len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));
|
||||
|
||||
/* There's nothing to do if the data hasn't changed */
|
||||
if (hdev->adv_data_len == len &&
|
||||
|
||||
+12
-5
@@ -336,7 +336,7 @@ static int iso_connect_bis(struct sock *sk)
|
||||
struct hci_dev *hdev;
|
||||
int err;
|
||||
|
||||
BT_DBG("%pMR", &iso_pi(sk)->src);
|
||||
BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid);
|
||||
|
||||
hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
|
||||
iso_pi(sk)->src_type);
|
||||
@@ -365,7 +365,7 @@ static int iso_connect_bis(struct sock *sk)
|
||||
|
||||
/* Just bind if DEFER_SETUP has been set */
|
||||
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
|
||||
hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst,
|
||||
hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid,
|
||||
&iso_pi(sk)->qos, iso_pi(sk)->base_len,
|
||||
iso_pi(sk)->base);
|
||||
if (IS_ERR(hcon)) {
|
||||
@@ -375,12 +375,16 @@ static int iso_connect_bis(struct sock *sk)
|
||||
} else {
|
||||
hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst,
|
||||
le_addr_type(iso_pi(sk)->dst_type),
|
||||
&iso_pi(sk)->qos, iso_pi(sk)->base_len,
|
||||
iso_pi(sk)->base);
|
||||
iso_pi(sk)->bc_sid, &iso_pi(sk)->qos,
|
||||
iso_pi(sk)->base_len, iso_pi(sk)->base);
|
||||
if (IS_ERR(hcon)) {
|
||||
err = PTR_ERR(hcon);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Update SID if it was not set */
|
||||
if (iso_pi(sk)->bc_sid == HCI_SID_INVALID)
|
||||
iso_pi(sk)->bc_sid = hcon->sid;
|
||||
}
|
||||
|
||||
conn = iso_conn_add(hcon);
|
||||
@@ -1337,10 +1341,13 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
|
||||
addr->sa_family = AF_BLUETOOTH;
|
||||
|
||||
if (peer) {
|
||||
struct hci_conn *hcon = iso_pi(sk)->conn ?
|
||||
iso_pi(sk)->conn->hcon : NULL;
|
||||
|
||||
bacpy(&sa->iso_bdaddr, &iso_pi(sk)->dst);
|
||||
sa->iso_bdaddr_type = iso_pi(sk)->dst_type;
|
||||
|
||||
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
|
||||
if (hcon && hcon->type == BIS_LINK) {
|
||||
sa->iso_bc->bc_sid = iso_pi(sk)->bc_sid;
|
||||
sa->iso_bc->bc_num_bis = iso_pi(sk)->bc_num_bis;
|
||||
memcpy(sa->iso_bc->bc_bis, iso_pi(sk)->bc_bis,
|
||||
|
||||
@@ -5102,11 +5102,11 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
|
||||
u16 handle)
|
||||
__le16 handle)
|
||||
{
|
||||
struct mgmt_ev_adv_monitor_removed ev;
|
||||
|
||||
ev.monitor_handle = cpu_to_le16(handle);
|
||||
ev.monitor_handle = handle;
|
||||
|
||||
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user