]>
Commit | Line | Data |
---|---|---|
7f87a3cd SL |
1 | From 2530dd42cf909251594d1aa00c51ae026bf5926d Mon Sep 17 00:00:00 2001 |
2 | From: Sasha Levin <sashal@kernel.org> | |
3 | Date: Sun, 15 Aug 2021 20:17:15 +0800 | |
4 | Subject: Bluetooth: refactor set_exp_feature with a feature table | |
5 | ||
6 | From: Joseph Hwang <josephsih@chromium.org> | |
7 | ||
8 | [ Upstream commit 93fb70bc112e922def6e50b37e20ccfce0c67c0a ] | |
9 | ||
10 | This patch refactors the set_exp_feature with a feature table | |
11 | consisting of UUIDs and the corresponding callback functions. | |
12 | In this way, a new experimental feature setting function can be | |
13 | simply added with its UUID and callback function. | |
14 | ||
15 | Signed-off-by: Joseph Hwang <josephsih@chromium.org> | |
16 | Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | |
17 | Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input") | |
18 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
19 | --- | |
20 | net/bluetooth/mgmt.c | 248 +++++++++++++++++++++++++------------------ | |
21 | 1 file changed, 142 insertions(+), 106 deletions(-) | |
22 | ||
23 | diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c | |
24 | index fd8bdafb71a0e..8acfd9db00d63 100644 | |
25 | --- a/net/bluetooth/mgmt.c | |
26 | +++ b/net/bluetooth/mgmt.c | |
27 | @@ -3784,7 +3784,7 @@ static const u8 rpa_resolution_uuid[16] = { | |
28 | static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, | |
29 | void *data, u16 data_len) | |
30 | { | |
31 | - char buf[62]; /* Enough space for 3 features */ | |
32 | + char buf[62]; /* Enough space for 3 features */ | |
33 | struct mgmt_rp_read_exp_features_info *rp = (void *)buf; | |
34 | u16 idx = 0; | |
35 | u32 flags; | |
36 | @@ -3870,150 +3870,186 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip) | |
37 | } | |
38 | #endif | |
39 | ||
40 | -static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, | |
41 | - void *data, u16 data_len) | |
42 | +#define EXP_FEAT(_uuid, _set_func) \ | |
43 | +{ \ | |
44 | + .uuid = _uuid, \ | |
45 | + .set_func = _set_func, \ | |
46 | +} | |
47 | + | |
48 | +/* The zero key uuid is special. Multiple exp features are set through it. */ | |
49 | +static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev, | |
50 | + struct mgmt_cp_set_exp_feature *cp, u16 data_len) | |
51 | { | |
52 | - struct mgmt_cp_set_exp_feature *cp = data; | |
53 | struct mgmt_rp_set_exp_feature rp; | |
54 | ||
55 | - bt_dev_dbg(hdev, "sock %p", sk); | |
56 | - | |
57 | - if (!memcmp(cp->uuid, ZERO_KEY, 16)) { | |
58 | - memset(rp.uuid, 0, 16); | |
59 | - rp.flags = cpu_to_le32(0); | |
60 | + memset(rp.uuid, 0, 16); | |
61 | + rp.flags = cpu_to_le32(0); | |
62 | ||
63 | #ifdef CONFIG_BT_FEATURE_DEBUG | |
64 | - if (!hdev) { | |
65 | - bool changed = bt_dbg_get(); | |
66 | + if (!hdev) { | |
67 | + bool changed = bt_dbg_get(); | |
68 | ||
69 | - bt_dbg_set(false); | |
70 | + bt_dbg_set(false); | |
71 | ||
72 | - if (changed) | |
73 | - exp_debug_feature_changed(false, sk); | |
74 | - } | |
75 | + if (changed) | |
76 | + exp_debug_feature_changed(false, sk); | |
77 | + } | |
78 | #endif | |
79 | ||
80 | - if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) { | |
81 | - bool changed = hci_dev_test_flag(hdev, | |
82 | - HCI_ENABLE_LL_PRIVACY); | |
83 | + if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) { | |
84 | + bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
85 | ||
86 | - hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
87 | + hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
88 | ||
89 | - if (changed) | |
90 | - exp_ll_privacy_feature_changed(false, hdev, sk); | |
91 | - } | |
92 | + if (changed) | |
93 | + exp_ll_privacy_feature_changed(false, hdev, sk); | |
94 | + } | |
95 | ||
96 | - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
97 | + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
98 | ||
99 | - return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, | |
100 | - MGMT_OP_SET_EXP_FEATURE, 0, | |
101 | - &rp, sizeof(rp)); | |
102 | - } | |
103 | + return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, | |
104 | + MGMT_OP_SET_EXP_FEATURE, 0, | |
105 | + &rp, sizeof(rp)); | |
106 | +} | |
107 | ||
108 | #ifdef CONFIG_BT_FEATURE_DEBUG | |
109 | - if (!memcmp(cp->uuid, debug_uuid, 16)) { | |
110 | - bool val, changed; | |
111 | - int err; | |
112 | +static int set_debug_func(struct sock *sk, struct hci_dev *hdev, | |
113 | + struct mgmt_cp_set_exp_feature *cp, u16 data_len) | |
114 | +{ | |
115 | + struct mgmt_rp_set_exp_feature rp; | |
116 | ||
117 | - /* Command requires to use the non-controller index */ | |
118 | - if (hdev) | |
119 | - return mgmt_cmd_status(sk, hdev->id, | |
120 | - MGMT_OP_SET_EXP_FEATURE, | |
121 | - MGMT_STATUS_INVALID_INDEX); | |
122 | + bool val, changed; | |
123 | + int err; | |
124 | ||
125 | - /* Parameters are limited to a single octet */ | |
126 | - if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) | |
127 | - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
128 | - MGMT_OP_SET_EXP_FEATURE, | |
129 | - MGMT_STATUS_INVALID_PARAMS); | |
130 | + /* Command requires to use the non-controller index */ | |
131 | + if (hdev) | |
132 | + return mgmt_cmd_status(sk, hdev->id, | |
133 | + MGMT_OP_SET_EXP_FEATURE, | |
134 | + MGMT_STATUS_INVALID_INDEX); | |
135 | ||
136 | - /* Only boolean on/off is supported */ | |
137 | - if (cp->param[0] != 0x00 && cp->param[0] != 0x01) | |
138 | - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
139 | - MGMT_OP_SET_EXP_FEATURE, | |
140 | - MGMT_STATUS_INVALID_PARAMS); | |
141 | + /* Parameters are limited to a single octet */ | |
142 | + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) | |
143 | + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
144 | + MGMT_OP_SET_EXP_FEATURE, | |
145 | + MGMT_STATUS_INVALID_PARAMS); | |
146 | ||
147 | - val = !!cp->param[0]; | |
148 | - changed = val ? !bt_dbg_get() : bt_dbg_get(); | |
149 | - bt_dbg_set(val); | |
150 | + /* Only boolean on/off is supported */ | |
151 | + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) | |
152 | + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
153 | + MGMT_OP_SET_EXP_FEATURE, | |
154 | + MGMT_STATUS_INVALID_PARAMS); | |
155 | ||
156 | - memcpy(rp.uuid, debug_uuid, 16); | |
157 | - rp.flags = cpu_to_le32(val ? BIT(0) : 0); | |
158 | + val = !!cp->param[0]; | |
159 | + changed = val ? !bt_dbg_get() : bt_dbg_get(); | |
160 | + bt_dbg_set(val); | |
161 | ||
162 | - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
163 | + memcpy(rp.uuid, debug_uuid, 16); | |
164 | + rp.flags = cpu_to_le32(val ? BIT(0) : 0); | |
165 | ||
166 | - err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, | |
167 | - MGMT_OP_SET_EXP_FEATURE, 0, | |
168 | - &rp, sizeof(rp)); | |
169 | + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
170 | ||
171 | - if (changed) | |
172 | - exp_debug_feature_changed(val, sk); | |
173 | + err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, | |
174 | + MGMT_OP_SET_EXP_FEATURE, 0, | |
175 | + &rp, sizeof(rp)); | |
176 | ||
177 | - return err; | |
178 | - } | |
179 | + if (changed) | |
180 | + exp_debug_feature_changed(val, sk); | |
181 | + | |
182 | + return err; | |
183 | +} | |
184 | #endif | |
185 | ||
186 | - if (!memcmp(cp->uuid, rpa_resolution_uuid, 16)) { | |
187 | - bool val, changed; | |
188 | - int err; | |
189 | - u32 flags; | |
190 | +static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev, | |
191 | + struct mgmt_cp_set_exp_feature *cp, | |
192 | + u16 data_len) | |
193 | +{ | |
194 | + struct mgmt_rp_set_exp_feature rp; | |
195 | + bool val, changed; | |
196 | + int err; | |
197 | + u32 flags; | |
198 | + | |
199 | + /* Command requires to use the controller index */ | |
200 | + if (!hdev) | |
201 | + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
202 | + MGMT_OP_SET_EXP_FEATURE, | |
203 | + MGMT_STATUS_INVALID_INDEX); | |
204 | ||
205 | - /* Command requires to use the controller index */ | |
206 | - if (!hdev) | |
207 | - return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | |
208 | - MGMT_OP_SET_EXP_FEATURE, | |
209 | - MGMT_STATUS_INVALID_INDEX); | |
210 | + /* Changes can only be made when controller is powered down */ | |
211 | + if (hdev_is_powered(hdev)) | |
212 | + return mgmt_cmd_status(sk, hdev->id, | |
213 | + MGMT_OP_SET_EXP_FEATURE, | |
214 | + MGMT_STATUS_REJECTED); | |
215 | ||
216 | - /* Changes can only be made when controller is powered down */ | |
217 | - if (hdev_is_powered(hdev)) | |
218 | - return mgmt_cmd_status(sk, hdev->id, | |
219 | - MGMT_OP_SET_EXP_FEATURE, | |
220 | - MGMT_STATUS_REJECTED); | |
221 | + /* Parameters are limited to a single octet */ | |
222 | + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) | |
223 | + return mgmt_cmd_status(sk, hdev->id, | |
224 | + MGMT_OP_SET_EXP_FEATURE, | |
225 | + MGMT_STATUS_INVALID_PARAMS); | |
226 | ||
227 | - /* Parameters are limited to a single octet */ | |
228 | - if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) | |
229 | - return mgmt_cmd_status(sk, hdev->id, | |
230 | - MGMT_OP_SET_EXP_FEATURE, | |
231 | - MGMT_STATUS_INVALID_PARAMS); | |
232 | + /* Only boolean on/off is supported */ | |
233 | + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) | |
234 | + return mgmt_cmd_status(sk, hdev->id, | |
235 | + MGMT_OP_SET_EXP_FEATURE, | |
236 | + MGMT_STATUS_INVALID_PARAMS); | |
237 | ||
238 | - /* Only boolean on/off is supported */ | |
239 | - if (cp->param[0] != 0x00 && cp->param[0] != 0x01) | |
240 | - return mgmt_cmd_status(sk, hdev->id, | |
241 | - MGMT_OP_SET_EXP_FEATURE, | |
242 | - MGMT_STATUS_INVALID_PARAMS); | |
243 | + val = !!cp->param[0]; | |
244 | ||
245 | - val = !!cp->param[0]; | |
246 | + if (val) { | |
247 | + changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
248 | + hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
249 | + hci_dev_clear_flag(hdev, HCI_ADVERTISING); | |
250 | ||
251 | - if (val) { | |
252 | - changed = !hci_dev_test_flag(hdev, | |
253 | - HCI_ENABLE_LL_PRIVACY); | |
254 | - hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
255 | - hci_dev_clear_flag(hdev, HCI_ADVERTISING); | |
256 | + /* Enable LL privacy + supported settings changed */ | |
257 | + flags = BIT(0) | BIT(1); | |
258 | + } else { | |
259 | + changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
260 | + hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
261 | ||
262 | - /* Enable LL privacy + supported settings changed */ | |
263 | - flags = BIT(0) | BIT(1); | |
264 | - } else { | |
265 | - changed = hci_dev_test_flag(hdev, | |
266 | - HCI_ENABLE_LL_PRIVACY); | |
267 | - hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); | |
268 | + /* Disable LL privacy + supported settings changed */ | |
269 | + flags = BIT(1); | |
270 | + } | |
271 | ||
272 | - /* Disable LL privacy + supported settings changed */ | |
273 | - flags = BIT(1); | |
274 | - } | |
275 | + memcpy(rp.uuid, rpa_resolution_uuid, 16); | |
276 | + rp.flags = cpu_to_le32(flags); | |
277 | ||
278 | - memcpy(rp.uuid, rpa_resolution_uuid, 16); | |
279 | - rp.flags = cpu_to_le32(flags); | |
280 | + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
281 | ||
282 | - hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | |
283 | + err = mgmt_cmd_complete(sk, hdev->id, | |
284 | + MGMT_OP_SET_EXP_FEATURE, 0, | |
285 | + &rp, sizeof(rp)); | |
286 | ||
287 | - err = mgmt_cmd_complete(sk, hdev->id, | |
288 | - MGMT_OP_SET_EXP_FEATURE, 0, | |
289 | - &rp, sizeof(rp)); | |
290 | + if (changed) | |
291 | + exp_ll_privacy_feature_changed(val, hdev, sk); | |
292 | ||
293 | - if (changed) | |
294 | - exp_ll_privacy_feature_changed(val, hdev, sk); | |
295 | + return err; | |
296 | +} | |
297 | ||
298 | - return err; | |
299 | +static const struct mgmt_exp_feature { | |
300 | + const u8 *uuid; | |
301 | + int (*set_func)(struct sock *sk, struct hci_dev *hdev, | |
302 | + struct mgmt_cp_set_exp_feature *cp, u16 data_len); | |
303 | +} exp_features[] = { | |
304 | + EXP_FEAT(ZERO_KEY, set_zero_key_func), | |
305 | +#ifdef CONFIG_BT_FEATURE_DEBUG | |
306 | + EXP_FEAT(debug_uuid, set_debug_func), | |
307 | +#endif | |
308 | + EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func), | |
309 | + | |
310 | + /* end with a null feature */ | |
311 | + EXP_FEAT(NULL, NULL) | |
312 | +}; | |
313 | + | |
314 | +static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, | |
315 | + void *data, u16 data_len) | |
316 | +{ | |
317 | + struct mgmt_cp_set_exp_feature *cp = data; | |
318 | + size_t i = 0; | |
319 | + | |
320 | + bt_dev_dbg(hdev, "sock %p", sk); | |
321 | + | |
322 | + for (i = 0; exp_features[i].uuid; i++) { | |
323 | + if (!memcmp(cp->uuid, exp_features[i].uuid, 16)) | |
324 | + return exp_features[i].set_func(sk, hdev, cp, data_len); | |
325 | } | |
326 | ||
327 | return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE, | |
328 | -- | |
329 | 2.43.0 | |
330 |