]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.10/bluetooth-support-the-quality-report-events.patch
6.1-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.10 / bluetooth-support-the-quality-report-events.patch
1 From e3e2c7a31fbb58c63dfa1ac477ee297e979f7eab Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Sun, 15 Aug 2021 20:17:16 +0800
4 Subject: Bluetooth: Support the quality report events
5
6 From: Joseph Hwang <josephsih@chromium.org>
7
8 [ Upstream commit ae7d925b5c0432c058fd175a70f1de6eee7a3f89 ]
9
10 This patch allows a user space process to enable/disable the quality
11 report events dynamically through the set experimental feature mgmt
12 interface.
13
14 Since the quality report feature needs to invoke the callback function
15 provided by the driver, i.e., hdev->set_quality_report, a valid
16 controller index is required.
17
18 Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
19 Signed-off-by: Joseph Hwang <josephsih@chromium.org>
20 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
21 Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input")
22 Signed-off-by: Sasha Levin <sashal@kernel.org>
23 ---
24 include/net/bluetooth/hci.h | 1 +
25 include/net/bluetooth/hci_core.h | 2 +
26 net/bluetooth/mgmt.c | 109 ++++++++++++++++++++++++++++++-
27 3 files changed, 111 insertions(+), 1 deletion(-)
28
29 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
30 index ede7a153c69a5..0e36974da384c 100644
31 --- a/include/net/bluetooth/hci.h
32 +++ b/include/net/bluetooth/hci.h
33 @@ -329,6 +329,7 @@ enum {
34 HCI_ENABLE_LL_PRIVACY,
35 HCI_CMD_PENDING,
36 HCI_FORCE_NO_MITM,
37 + HCI_QUALITY_REPORT,
38
39 __HCI_NUM_FLAGS,
40 };
41 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
42 index daafca376cb7c..c8f11dde54837 100644
43 --- a/include/net/bluetooth/hci_core.h
44 +++ b/include/net/bluetooth/hci_core.h
45 @@ -586,6 +586,7 @@ struct hci_dev {
46 int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
47 void (*cmd_timeout)(struct hci_dev *hdev);
48 bool (*prevent_wake)(struct hci_dev *hdev);
49 + int (*set_quality_report)(struct hci_dev *hdev, bool enable);
50 };
51
52 #define HCI_PHY_HANDLE(handle) (handle & 0xff)
53 @@ -739,6 +740,7 @@ extern struct mutex hci_cb_list_lock;
54 hci_dev_clear_flag(hdev, HCI_LE_ADV); \
55 hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);\
56 hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ); \
57 + hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); \
58 } while (0)
59
60 /* ----- HCI interface to upper protocols ----- */
61 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
62 index 8acfd9db00d63..b19ad142b8ba5 100644
63 --- a/net/bluetooth/mgmt.c
64 +++ b/net/bluetooth/mgmt.c
65 @@ -3769,6 +3769,12 @@ static const u8 debug_uuid[16] = {
66 };
67 #endif
68
69 +/* 330859bc-7506-492d-9370-9a6f0614037f */
70 +static const u8 quality_report_uuid[16] = {
71 + 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93,
72 + 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33,
73 +};
74 +
75 /* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
76 static const u8 simult_central_periph_uuid[16] = {
77 0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
78 @@ -3784,7 +3790,7 @@ static const u8 rpa_resolution_uuid[16] = {
79 static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
80 void *data, u16 data_len)
81 {
82 - char buf[62]; /* Enough space for 3 features */
83 + char buf[82]; /* Enough space for 4 features: 2 + 20 * 4 */
84 struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
85 u16 idx = 0;
86 u32 flags;
87 @@ -3828,6 +3834,24 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
88 idx++;
89 }
90
91 + if (hdev) {
92 + if (hdev->set_quality_report) {
93 + /* BIT(0): indicating if set_quality_report is
94 + * supported by controller.
95 + */
96 + flags = BIT(0);
97 +
98 + /* BIT(1): indicating if the feature is enabled. */
99 + if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
100 + flags |= BIT(1);
101 + } else {
102 + flags = 0;
103 + }
104 + memcpy(rp->features[idx].uuid, quality_report_uuid, 16);
105 + rp->features[idx].flags = cpu_to_le32(flags);
106 + idx++;
107 + }
108 +
109 rp->feature_count = cpu_to_le16(idx);
110
111 /* After reading the experimental features information, enable
112 @@ -3870,6 +3894,19 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
113 }
114 #endif
115
116 +static int exp_quality_report_feature_changed(bool enabled, struct sock *skip)
117 +{
118 + struct mgmt_ev_exp_feature_changed ev;
119 +
120 + memset(&ev, 0, sizeof(ev));
121 + memcpy(ev.uuid, quality_report_uuid, 16);
122 + ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
123 +
124 + return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
125 + &ev, sizeof(ev),
126 + HCI_MGMT_EXP_FEATURE_EVENTS, skip);
127 +}
128 +
129 #define EXP_FEAT(_uuid, _set_func) \
130 { \
131 .uuid = _uuid, \
132 @@ -4024,6 +4061,75 @@ static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
133 return err;
134 }
135
136 +static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
137 + struct mgmt_cp_set_exp_feature *cp,
138 + u16 data_len)
139 +{
140 + struct mgmt_rp_set_exp_feature rp;
141 + bool val, changed;
142 + int err;
143 +
144 + /* Command requires to use a valid controller index */
145 + if (!hdev)
146 + return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
147 + MGMT_OP_SET_EXP_FEATURE,
148 + MGMT_STATUS_INVALID_INDEX);
149 +
150 + /* Parameters are limited to a single octet */
151 + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
152 + return mgmt_cmd_status(sk, hdev->id,
153 + MGMT_OP_SET_EXP_FEATURE,
154 + MGMT_STATUS_INVALID_PARAMS);
155 +
156 + /* Only boolean on/off is supported */
157 + if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
158 + return mgmt_cmd_status(sk, hdev->id,
159 + MGMT_OP_SET_EXP_FEATURE,
160 + MGMT_STATUS_INVALID_PARAMS);
161 +
162 + hci_req_sync_lock(hdev);
163 +
164 + val = !!cp->param[0];
165 + changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
166 +
167 + if (!hdev->set_quality_report) {
168 + err = mgmt_cmd_status(sk, hdev->id,
169 + MGMT_OP_SET_EXP_FEATURE,
170 + MGMT_STATUS_NOT_SUPPORTED);
171 + goto unlock_quality_report;
172 + }
173 +
174 + if (changed) {
175 + err = hdev->set_quality_report(hdev, val);
176 + if (err) {
177 + err = mgmt_cmd_status(sk, hdev->id,
178 + MGMT_OP_SET_EXP_FEATURE,
179 + MGMT_STATUS_FAILED);
180 + goto unlock_quality_report;
181 + }
182 + if (val)
183 + hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
184 + else
185 + hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
186 + }
187 +
188 + bt_dev_dbg(hdev, "quality report enable %d changed %d", val, changed);
189 +
190 + memcpy(rp.uuid, quality_report_uuid, 16);
191 + rp.flags = cpu_to_le32(val ? BIT(0) : 0);
192 + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
193 + err = mgmt_cmd_complete(sk, hdev->id,
194 + MGMT_OP_SET_EXP_FEATURE, 0,
195 + &rp, sizeof(rp));
196 +
197 + if (changed)
198 + exp_quality_report_feature_changed(val, sk);
199 +
200 +unlock_quality_report:
201 + hci_req_sync_unlock(hdev);
202 + return err;
203 +}
204 +
205 static const struct mgmt_exp_feature {
206 const u8 *uuid;
207 int (*set_func)(struct sock *sk, struct hci_dev *hdev,
208 @@ -4034,6 +4140,7 @@ static const struct mgmt_exp_feature {
209 EXP_FEAT(debug_uuid, set_debug_func),
210 #endif
211 EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
212 + EXP_FEAT(quality_report_uuid, set_quality_report_func),
213
214 /* end with a null feature */
215 EXP_FEAT(NULL, NULL)
216 --
217 2.43.0
218