xref: /linux/net/bluetooth/mgmt_config.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 /*
4  * Copyright (C) 2020 Google Corporation
5  */
6 
7 #include <net/bluetooth/bluetooth.h>
8 #include <net/bluetooth/hci_core.h>
9 #include <net/bluetooth/mgmt.h>
10 
11 #include "mgmt_util.h"
12 #include "mgmt_config.h"
13 
14 #define HDEV_PARAM_U16(_param_name_) \
15 	struct {\
16 		struct mgmt_tlv entry; \
17 		__le16 value; \
18 	} __packed _param_name_
19 
20 #define HDEV_PARAM_U8(_param_name_) \
21 	struct {\
22 		struct mgmt_tlv entry; \
23 		__u8 value; \
24 	} __packed _param_name_
25 
26 #define TLV_SET_U16(_param_code_, _param_name_) \
27 	{ \
28 		{ cpu_to_le16(_param_code_), sizeof(__u16) }, \
29 		cpu_to_le16(hdev->_param_name_) \
30 	}
31 
32 #define TLV_SET_U8(_param_code_, _param_name_) \
33 	{ \
34 		{ cpu_to_le16(_param_code_), sizeof(__u8) }, \
35 		hdev->_param_name_ \
36 	}
37 
38 #define TLV_SET_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \
39 	{ \
40 		{ cpu_to_le16(_param_code_), sizeof(__u16) }, \
41 		cpu_to_le16(jiffies_to_msecs(hdev->_param_name_)) \
42 	}
43 
read_def_system_config(struct sock * sk,struct hci_dev * hdev,void * data,u16 data_len)44 int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
45 			   u16 data_len)
46 {
47 	int ret;
48 	struct mgmt_rp_read_def_system_config {
49 		/* Please see mgmt-api.txt for documentation of these values */
50 		HDEV_PARAM_U16(def_page_scan_type);
51 		HDEV_PARAM_U16(def_page_scan_int);
52 		HDEV_PARAM_U16(def_page_scan_window);
53 		HDEV_PARAM_U16(def_inq_scan_type);
54 		HDEV_PARAM_U16(def_inq_scan_int);
55 		HDEV_PARAM_U16(def_inq_scan_window);
56 		HDEV_PARAM_U16(def_br_lsto);
57 		HDEV_PARAM_U16(def_page_timeout);
58 		HDEV_PARAM_U16(sniff_min_interval);
59 		HDEV_PARAM_U16(sniff_max_interval);
60 		HDEV_PARAM_U16(le_adv_min_interval);
61 		HDEV_PARAM_U16(le_adv_max_interval);
62 		HDEV_PARAM_U16(def_multi_adv_rotation_duration);
63 		HDEV_PARAM_U16(le_scan_interval);
64 		HDEV_PARAM_U16(le_scan_window);
65 		HDEV_PARAM_U16(le_scan_int_suspend);
66 		HDEV_PARAM_U16(le_scan_window_suspend);
67 		HDEV_PARAM_U16(le_scan_int_discovery);
68 		HDEV_PARAM_U16(le_scan_window_discovery);
69 		HDEV_PARAM_U16(le_scan_int_adv_monitor);
70 		HDEV_PARAM_U16(le_scan_window_adv_monitor);
71 		HDEV_PARAM_U16(le_scan_int_connect);
72 		HDEV_PARAM_U16(le_scan_window_connect);
73 		HDEV_PARAM_U16(le_conn_min_interval);
74 		HDEV_PARAM_U16(le_conn_max_interval);
75 		HDEV_PARAM_U16(le_conn_latency);
76 		HDEV_PARAM_U16(le_supv_timeout);
77 		HDEV_PARAM_U16(def_le_autoconnect_timeout);
78 		HDEV_PARAM_U16(advmon_allowlist_duration);
79 		HDEV_PARAM_U16(advmon_no_filter_duration);
80 		HDEV_PARAM_U8(enable_advmon_interleave_scan);
81 	} __packed rp = {
82 		TLV_SET_U16(0x0000, def_page_scan_type),
83 		TLV_SET_U16(0x0001, def_page_scan_int),
84 		TLV_SET_U16(0x0002, def_page_scan_window),
85 		TLV_SET_U16(0x0003, def_inq_scan_type),
86 		TLV_SET_U16(0x0004, def_inq_scan_int),
87 		TLV_SET_U16(0x0005, def_inq_scan_window),
88 		TLV_SET_U16(0x0006, def_br_lsto),
89 		TLV_SET_U16(0x0007, def_page_timeout),
90 		TLV_SET_U16(0x0008, sniff_min_interval),
91 		TLV_SET_U16(0x0009, sniff_max_interval),
92 		TLV_SET_U16(0x000a, le_adv_min_interval),
93 		TLV_SET_U16(0x000b, le_adv_max_interval),
94 		TLV_SET_U16(0x000c, def_multi_adv_rotation_duration),
95 		TLV_SET_U16(0x000d, le_scan_interval),
96 		TLV_SET_U16(0x000e, le_scan_window),
97 		TLV_SET_U16(0x000f, le_scan_int_suspend),
98 		TLV_SET_U16(0x0010, le_scan_window_suspend),
99 		TLV_SET_U16(0x0011, le_scan_int_discovery),
100 		TLV_SET_U16(0x0012, le_scan_window_discovery),
101 		TLV_SET_U16(0x0013, le_scan_int_adv_monitor),
102 		TLV_SET_U16(0x0014, le_scan_window_adv_monitor),
103 		TLV_SET_U16(0x0015, le_scan_int_connect),
104 		TLV_SET_U16(0x0016, le_scan_window_connect),
105 		TLV_SET_U16(0x0017, le_conn_min_interval),
106 		TLV_SET_U16(0x0018, le_conn_max_interval),
107 		TLV_SET_U16(0x0019, le_conn_latency),
108 		TLV_SET_U16(0x001a, le_supv_timeout),
109 		TLV_SET_U16_JIFFIES_TO_MSECS(0x001b,
110 					     def_le_autoconnect_timeout),
111 		TLV_SET_U16(0x001d, advmon_allowlist_duration),
112 		TLV_SET_U16(0x001e, advmon_no_filter_duration),
113 		TLV_SET_U8(0x001f, enable_advmon_interleave_scan),
114 	};
115 
116 	bt_dev_dbg(hdev, "sock %p", sk);
117 
118 	ret = mgmt_cmd_complete(sk, hdev->id,
119 				MGMT_OP_READ_DEF_SYSTEM_CONFIG,
120 				0, &rp, sizeof(rp));
121 	return ret;
122 }
123 
124 #define TO_TLV(x)		((struct mgmt_tlv *)(x))
125 #define TLV_GET_LE16(tlv)	le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value)))
126 #define TLV_GET_U8(tlv)		(*((__u8 *)(TO_TLV(tlv)->value)))
127 
set_def_system_config(struct sock * sk,struct hci_dev * hdev,void * data,u16 data_len)128 int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
129 			  u16 data_len)
130 {
131 	u16 buffer_left = data_len;
132 	u8 *buffer = data;
133 
134 	if (buffer_left < sizeof(struct mgmt_tlv)) {
135 		return mgmt_cmd_status(sk, hdev->id,
136 				       MGMT_OP_SET_DEF_SYSTEM_CONFIG,
137 				       MGMT_STATUS_INVALID_PARAMS);
138 	}
139 
140 	/* First pass to validate the tlv */
141 	while (buffer_left >= sizeof(struct mgmt_tlv)) {
142 		const u8 len = TO_TLV(buffer)->length;
143 		size_t exp_type_len;
144 		const u16 exp_len = sizeof(struct mgmt_tlv) +
145 				    len;
146 		const u16 type = le16_to_cpu(TO_TLV(buffer)->type);
147 
148 		if (buffer_left < exp_len) {
149 			bt_dev_warn(hdev, "invalid len left %u, exp >= %u",
150 				    buffer_left, exp_len);
151 
152 			return mgmt_cmd_status(sk, hdev->id,
153 					MGMT_OP_SET_DEF_SYSTEM_CONFIG,
154 					MGMT_STATUS_INVALID_PARAMS);
155 		}
156 
157 		/* Please see mgmt-api.txt for documentation of these values */
158 		switch (type) {
159 		case 0x0000:
160 		case 0x0001:
161 		case 0x0002:
162 		case 0x0003:
163 		case 0x0004:
164 		case 0x0005:
165 		case 0x0006:
166 		case 0x0007:
167 		case 0x0008:
168 		case 0x0009:
169 		case 0x000a:
170 		case 0x000b:
171 		case 0x000c:
172 		case 0x000d:
173 		case 0x000e:
174 		case 0x000f:
175 		case 0x0010:
176 		case 0x0011:
177 		case 0x0012:
178 		case 0x0013:
179 		case 0x0014:
180 		case 0x0015:
181 		case 0x0016:
182 		case 0x0017:
183 		case 0x0018:
184 		case 0x0019:
185 		case 0x001a:
186 		case 0x001b:
187 		case 0x001d:
188 		case 0x001e:
189 			exp_type_len = sizeof(u16);
190 			break;
191 		case 0x001f:
192 			exp_type_len = sizeof(u8);
193 			break;
194 		default:
195 			exp_type_len = 0;
196 			bt_dev_warn(hdev, "unsupported parameter %u", type);
197 			break;
198 		}
199 
200 		if (exp_type_len && len != exp_type_len) {
201 			bt_dev_warn(hdev, "invalid length %d, exp %zu for type %u",
202 				    len, exp_type_len, type);
203 
204 			return mgmt_cmd_status(sk, hdev->id,
205 				MGMT_OP_SET_DEF_SYSTEM_CONFIG,
206 				MGMT_STATUS_INVALID_PARAMS);
207 		}
208 
209 		buffer_left -= exp_len;
210 		buffer += exp_len;
211 	}
212 
213 	buffer_left = data_len;
214 	buffer = data;
215 	while (buffer_left >= sizeof(struct mgmt_tlv)) {
216 		const u8 len = TO_TLV(buffer)->length;
217 		const u16 exp_len = sizeof(struct mgmt_tlv) +
218 				    len;
219 		const u16 type = le16_to_cpu(TO_TLV(buffer)->type);
220 
221 		switch (type) {
222 		case 0x0000:
223 			hdev->def_page_scan_type = TLV_GET_LE16(buffer);
224 			break;
225 		case 0x0001:
226 			hdev->def_page_scan_int = TLV_GET_LE16(buffer);
227 			break;
228 		case 0x0002:
229 			hdev->def_page_scan_window = TLV_GET_LE16(buffer);
230 			break;
231 		case 0x0003:
232 			hdev->def_inq_scan_type = TLV_GET_LE16(buffer);
233 			break;
234 		case 0x0004:
235 			hdev->def_inq_scan_int = TLV_GET_LE16(buffer);
236 			break;
237 		case 0x0005:
238 			hdev->def_inq_scan_window = TLV_GET_LE16(buffer);
239 			break;
240 		case 0x0006:
241 			hdev->def_br_lsto = TLV_GET_LE16(buffer);
242 			break;
243 		case 0x0007:
244 			hdev->def_page_timeout = TLV_GET_LE16(buffer);
245 			break;
246 		case 0x0008:
247 			hdev->sniff_min_interval = TLV_GET_LE16(buffer);
248 			break;
249 		case 0x0009:
250 			hdev->sniff_max_interval = TLV_GET_LE16(buffer);
251 			break;
252 		case 0x000a:
253 			hdev->le_adv_min_interval = TLV_GET_LE16(buffer);
254 			break;
255 		case 0x000b:
256 			hdev->le_adv_max_interval = TLV_GET_LE16(buffer);
257 			break;
258 		case 0x000c:
259 			hdev->def_multi_adv_rotation_duration =
260 							   TLV_GET_LE16(buffer);
261 			break;
262 		case 0x000d:
263 			hdev->le_scan_interval = TLV_GET_LE16(buffer);
264 			break;
265 		case 0x000e:
266 			hdev->le_scan_window = TLV_GET_LE16(buffer);
267 			break;
268 		case 0x000f:
269 			hdev->le_scan_int_suspend = TLV_GET_LE16(buffer);
270 			break;
271 		case 0x0010:
272 			hdev->le_scan_window_suspend = TLV_GET_LE16(buffer);
273 			break;
274 		case 0x0011:
275 			hdev->le_scan_int_discovery = TLV_GET_LE16(buffer);
276 			break;
277 		case 0x00012:
278 			hdev->le_scan_window_discovery = TLV_GET_LE16(buffer);
279 			break;
280 		case 0x00013:
281 			hdev->le_scan_int_adv_monitor = TLV_GET_LE16(buffer);
282 			break;
283 		case 0x00014:
284 			hdev->le_scan_window_adv_monitor = TLV_GET_LE16(buffer);
285 			break;
286 		case 0x00015:
287 			hdev->le_scan_int_connect = TLV_GET_LE16(buffer);
288 			break;
289 		case 0x00016:
290 			hdev->le_scan_window_connect = TLV_GET_LE16(buffer);
291 			break;
292 		case 0x00017:
293 			hdev->le_conn_min_interval = TLV_GET_LE16(buffer);
294 			break;
295 		case 0x00018:
296 			hdev->le_conn_max_interval = TLV_GET_LE16(buffer);
297 			break;
298 		case 0x00019:
299 			hdev->le_conn_latency = TLV_GET_LE16(buffer);
300 			break;
301 		case 0x0001a:
302 			hdev->le_supv_timeout = TLV_GET_LE16(buffer);
303 			break;
304 		case 0x0001b:
305 			hdev->def_le_autoconnect_timeout =
306 					msecs_to_jiffies(TLV_GET_LE16(buffer));
307 			break;
308 		case 0x0001d:
309 			hdev->advmon_allowlist_duration = TLV_GET_LE16(buffer);
310 			break;
311 		case 0x0001e:
312 			hdev->advmon_no_filter_duration = TLV_GET_LE16(buffer);
313 			break;
314 		case 0x0001f:
315 			hdev->enable_advmon_interleave_scan = TLV_GET_U8(buffer);
316 			break;
317 		default:
318 			bt_dev_warn(hdev, "unsupported parameter %u", type);
319 			break;
320 		}
321 
322 		buffer_left -= exp_len;
323 		buffer += exp_len;
324 	}
325 
326 	return mgmt_cmd_complete(sk, hdev->id,
327 				 MGMT_OP_SET_DEF_SYSTEM_CONFIG, 0, NULL, 0);
328 }
329 
read_def_runtime_config(struct sock * sk,struct hci_dev * hdev,void * data,u16 data_len)330 int read_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data,
331 			    u16 data_len)
332 {
333 	bt_dev_dbg(hdev, "sock %p", sk);
334 
335 	return mgmt_cmd_complete(sk, hdev->id,
336 				 MGMT_OP_READ_DEF_RUNTIME_CONFIG, 0, NULL, 0);
337 }
338 
set_def_runtime_config(struct sock * sk,struct hci_dev * hdev,void * data,u16 data_len)339 int set_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data,
340 			   u16 data_len)
341 {
342 	bt_dev_dbg(hdev, "sock %p", sk);
343 
344 	return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEF_SYSTEM_CONFIG,
345 			       MGMT_STATUS_INVALID_PARAMS);
346 }
347