Skip to content

Commit e1cff70

Browse files
committed
bluetooth: don't use bitmaps for random flag accesses
The bluetooth code uses our bitmap infrastructure for the two bits (!) of connection setup flags, and in the process causes odd problems when it converts between a bitmap and just the regular values of said bits. It's completely pointless to do things like bitmap_to_arr32() to convert a bitmap into a u32. It shoudln't have been a bitmap in the first place. The reason to use bitmaps is if you have arbitrary number of bits you want to manage (not two!), or if you rely on the atomicity guarantees of the bitmap setting and clearing. The code could use an "atomic_t" and use "atomic_or/andnot()" to set and clear the bit values, but considering that it then copies the bitmaps around with "bitmap_to_arr32()" and friends, there clearly cannot be a lot of atomicity requirements. So just use a regular integer. In the process, this avoids the warnings about erroneous use of bitmap_from_u64() which were triggered on 32-bit architectures when conversion from a u64 would access two words (and, surprise, surprise, only one word is needed - and indeed overkill - for a 2-bit bitmap). That was always problematic, but the compiler seems to notice it and warn about the invalid pattern only after commit 0a97953 ("lib: add bitmap_{from,to}_arr64") changed the exact implementation details of 'bitmap_from_u64()', as reported by Sudip Mukherjee and Stephen Rothwell. Fixes: fe92ee6 ("Bluetooth: hci_core: Rework hci_conn_params flags") Link: https://lore.kernel.org/all/YpyJ9qTNHJzz0FHY@debian/ Link: https://lore.kernel.org/all/20220606080631.0c3014f2@canb.auug.org.au/ Link: https://lore.kernel.org/all/20220605162537.1604762-1-yury.norov@gmail.com/ Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Reported-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com> Reviewed-by: Yury Norov <yury.norov@gmail.com> Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Cc: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent d717180 commit e1cff70

File tree

5 files changed

+27
-39
lines changed

5 files changed

+27
-39
lines changed

include/net/bluetooth/hci_core.h

+7-10
Original file line numberDiff line numberDiff line change
@@ -155,21 +155,18 @@ struct bdaddr_list_with_irk {
155155
u8 local_irk[16];
156156
};
157157

158+
/* Bitmask of connection flags */
158159
enum hci_conn_flags {
159-
HCI_CONN_FLAG_REMOTE_WAKEUP,
160-
HCI_CONN_FLAG_DEVICE_PRIVACY,
161-
162-
__HCI_CONN_NUM_FLAGS,
160+
HCI_CONN_FLAG_REMOTE_WAKEUP = 1,
161+
HCI_CONN_FLAG_DEVICE_PRIVACY = 2,
163162
};
164-
165-
/* Make sure number of flags doesn't exceed sizeof(current_flags) */
166-
static_assert(__HCI_CONN_NUM_FLAGS < 32);
163+
typedef u8 hci_conn_flags_t;
167164

168165
struct bdaddr_list_with_flags {
169166
struct list_head list;
170167
bdaddr_t bdaddr;
171168
u8 bdaddr_type;
172-
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
169+
hci_conn_flags_t flags;
173170
};
174171

175172
struct bt_uuid {
@@ -576,7 +573,7 @@ struct hci_dev {
576573
struct rfkill *rfkill;
577574

578575
DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
579-
DECLARE_BITMAP(conn_flags, __HCI_CONN_NUM_FLAGS);
576+
hci_conn_flags_t conn_flags;
580577

581578
__s8 adv_tx_power;
582579
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
@@ -775,7 +772,7 @@ struct hci_conn_params {
775772

776773
struct hci_conn *conn;
777774
bool explicit_connect;
778-
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
775+
hci_conn_flags_t flags;
779776
u8 privacy_mode;
780777
};
781778

net/bluetooth/hci_core.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -2153,7 +2153,7 @@ int hci_bdaddr_list_add_with_flags(struct list_head *list, bdaddr_t *bdaddr,
21532153

21542154
bacpy(&entry->bdaddr, bdaddr);
21552155
entry->bdaddr_type = type;
2156-
bitmap_from_u64(entry->flags, flags);
2156+
entry->flags = flags;
21572157

21582158
list_add(&entry->list, list);
21592159

@@ -2634,7 +2634,7 @@ int hci_register_dev(struct hci_dev *hdev)
26342634
* callback.
26352635
*/
26362636
if (hdev->wakeup)
2637-
set_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, hdev->conn_flags);
2637+
hdev->conn_flags |= HCI_CONN_FLAG_REMOTE_WAKEUP;
26382638

26392639
hci_sock_dev_event(hdev, HCI_DEV_REG);
26402640
hci_dev_hold(hdev);

net/bluetooth/hci_request.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ static int add_to_accept_list(struct hci_request *req,
482482

483483
/* During suspend, only wakeable devices can be in accept list */
484484
if (hdev->suspended &&
485-
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
485+
!(params->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
486486
return 0;
487487

488488
*num_entries += 1;

net/bluetooth/hci_sync.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
16371637
* indicates that LL Privacy has been enabled and
16381638
* HCI_OP_LE_SET_PRIVACY_MODE is supported.
16391639
*/
1640-
if (!test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, params->flags))
1640+
if (!(params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY))
16411641
return 0;
16421642

16431643
irk = hci_find_irk_by_addr(hdev, &params->addr, params->addr_type);
@@ -1666,7 +1666,7 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
16661666

16671667
/* During suspend, only wakeable devices can be in acceptlist */
16681668
if (hdev->suspended &&
1669-
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
1669+
!(params->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
16701670
return 0;
16711671

16721672
/* Select filter policy to accept all advertising */
@@ -4888,7 +4888,7 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
48884888
hci_clear_event_filter_sync(hdev);
48894889

48904890
list_for_each_entry(b, &hdev->accept_list, list) {
4891-
if (!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, b->flags))
4891+
if (!(b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
48924892
continue;
48934893

48944894
bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);

net/bluetooth/mgmt.c

+14-23
Original file line numberDiff line numberDiff line change
@@ -4013,10 +4013,11 @@ static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
40134013
memcpy(ev.uuid, rpa_resolution_uuid, 16);
40144014
ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
40154015

4016+
// Do we need to be atomic with the conn_flags?
40164017
if (enabled && privacy_mode_capable(hdev))
4017-
set_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
4018+
hdev->conn_flags |= HCI_CONN_FLAG_DEVICE_PRIVACY;
40184019
else
4019-
clear_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
4020+
hdev->conn_flags &= ~HCI_CONN_FLAG_DEVICE_PRIVACY;
40204021

40214022
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
40224023
&ev, sizeof(ev),
@@ -4435,8 +4436,7 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
44354436

44364437
hci_dev_lock(hdev);
44374438

4438-
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
4439-
__HCI_CONN_NUM_FLAGS);
4439+
supported_flags = hdev->conn_flags;
44404440

44414441
memset(&rp, 0, sizeof(rp));
44424442

@@ -4447,17 +4447,15 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
44474447
if (!br_params)
44484448
goto done;
44494449

4450-
bitmap_to_arr32(&current_flags, br_params->flags,
4451-
__HCI_CONN_NUM_FLAGS);
4450+
current_flags = br_params->flags;
44524451
} else {
44534452
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
44544453
le_addr_type(cp->addr.type));
44554454

44564455
if (!params)
44574456
goto done;
44584457

4459-
bitmap_to_arr32(&current_flags, params->flags,
4460-
__HCI_CONN_NUM_FLAGS);
4458+
current_flags = params->flags;
44614459
}
44624460

44634461
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
@@ -4502,8 +4500,8 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
45024500
&cp->addr.bdaddr, cp->addr.type,
45034501
__le32_to_cpu(current_flags));
45044502

4505-
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
4506-
__HCI_CONN_NUM_FLAGS);
4503+
// We should take hci_dev_lock() early, I think.. conn_flags can change
4504+
supported_flags = hdev->conn_flags;
45074505

45084506
if ((supported_flags | current_flags) != supported_flags) {
45094507
bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
@@ -4519,7 +4517,7 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
45194517
cp->addr.type);
45204518

45214519
if (br_params) {
4522-
bitmap_from_u64(br_params->flags, current_flags);
4520+
br_params->flags = current_flags;
45234521
status = MGMT_STATUS_SUCCESS;
45244522
} else {
45254523
bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
@@ -4529,15 +4527,11 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
45294527
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
45304528
le_addr_type(cp->addr.type));
45314529
if (params) {
4532-
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
4533-
4534-
bitmap_from_u64(flags, current_flags);
4535-
45364530
/* Devices using RPAs can only be programmed in the
45374531
* acceptlist LL Privacy has been enable otherwise they
45384532
* cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP.
45394533
*/
4540-
if (test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, flags) &&
4534+
if ((current_flags & HCI_CONN_FLAG_REMOTE_WAKEUP) &&
45414535
!use_ll_privacy(hdev) &&
45424536
hci_find_irk_by_addr(hdev, &params->addr,
45434537
params->addr_type)) {
@@ -4546,14 +4540,13 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
45464540
goto unlock;
45474541
}
45484542

4549-
bitmap_from_u64(params->flags, current_flags);
4543+
params->flags = current_flags;
45504544
status = MGMT_STATUS_SUCCESS;
45514545

45524546
/* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
45534547
* has been set.
45544548
*/
4555-
if (test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY,
4556-
params->flags))
4549+
if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
45574550
hci_update_passive_scan(hdev);
45584551
} else {
45594552
bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
@@ -7154,8 +7147,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
71547147
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
71557148
addr_type);
71567149
if (params)
7157-
bitmap_to_arr32(&current_flags, params->flags,
7158-
__HCI_CONN_NUM_FLAGS);
7150+
current_flags = params->flags;
71597151
}
71607152

71617153
err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
@@ -7164,8 +7156,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
71647156

71657157
added:
71667158
device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
7167-
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
7168-
__HCI_CONN_NUM_FLAGS);
7159+
supported_flags = hdev->conn_flags;
71697160
device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
71707161
supported_flags, current_flags);
71717162

0 commit comments

Comments
 (0)