]>
Commit | Line | Data |
---|---|---|
17896406 AM |
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_code_, _param_name_) \ | |
15 | { \ | |
16 | { cpu_to_le16(_param_code_), sizeof(__u16) }, \ | |
17 | { cpu_to_le16(hdev->_param_name_) } \ | |
18 | } | |
19 | ||
49b020c1 AM |
20 | #define HDEV_PARAM_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \ |
21 | { \ | |
22 | { cpu_to_le16(_param_code_), sizeof(__u16) }, \ | |
23 | { cpu_to_le16(jiffies_to_msecs(hdev->_param_name_)) } \ | |
24 | } | |
25 | ||
17896406 AM |
26 | int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, |
27 | u16 data_len) | |
28 | { | |
29 | struct { | |
30 | struct mgmt_tlv entry; | |
31 | union { | |
32 | /* This is a simplification for now since all values | |
33 | * are 16 bits. In the future, this code may need | |
34 | * refactoring to account for variable length values | |
35 | * and properly calculate the required buffer size. | |
36 | */ | |
37 | __le16 value; | |
38 | }; | |
39 | } __packed params[] = { | |
40 | /* Please see mgmt-api.txt for documentation of these values */ | |
41 | HDEV_PARAM_U16(0x0000, def_page_scan_type), | |
42 | HDEV_PARAM_U16(0x0001, def_page_scan_int), | |
43 | HDEV_PARAM_U16(0x0002, def_page_scan_window), | |
44 | HDEV_PARAM_U16(0x0003, def_inq_scan_type), | |
45 | HDEV_PARAM_U16(0x0004, def_inq_scan_int), | |
46 | HDEV_PARAM_U16(0x0005, def_inq_scan_window), | |
47 | HDEV_PARAM_U16(0x0006, def_br_lsto), | |
48 | HDEV_PARAM_U16(0x0007, def_page_timeout), | |
49 | HDEV_PARAM_U16(0x0008, sniff_min_interval), | |
50 | HDEV_PARAM_U16(0x0009, sniff_max_interval), | |
51 | HDEV_PARAM_U16(0x000a, le_adv_min_interval), | |
52 | HDEV_PARAM_U16(0x000b, le_adv_max_interval), | |
53 | HDEV_PARAM_U16(0x000c, def_multi_adv_rotation_duration), | |
54 | HDEV_PARAM_U16(0x000d, le_scan_interval), | |
55 | HDEV_PARAM_U16(0x000e, le_scan_window), | |
56 | HDEV_PARAM_U16(0x000f, le_scan_int_suspend), | |
57 | HDEV_PARAM_U16(0x0010, le_scan_window_suspend), | |
58 | HDEV_PARAM_U16(0x0011, le_scan_int_discovery), | |
59 | HDEV_PARAM_U16(0x0012, le_scan_window_discovery), | |
60 | HDEV_PARAM_U16(0x0013, le_scan_int_adv_monitor), | |
61 | HDEV_PARAM_U16(0x0014, le_scan_window_adv_monitor), | |
62 | HDEV_PARAM_U16(0x0015, le_scan_int_connect), | |
63 | HDEV_PARAM_U16(0x0016, le_scan_window_connect), | |
64 | HDEV_PARAM_U16(0x0017, le_conn_min_interval), | |
65 | HDEV_PARAM_U16(0x0018, le_conn_max_interval), | |
66 | HDEV_PARAM_U16(0x0019, le_conn_latency), | |
67 | HDEV_PARAM_U16(0x001a, le_supv_timeout), | |
49b020c1 AM |
68 | HDEV_PARAM_U16_JIFFIES_TO_MSECS(0x001b, |
69 | def_le_autoconnect_timeout), | |
17896406 AM |
70 | }; |
71 | struct mgmt_rp_read_def_system_config *rp = (void *)params; | |
72 | ||
73 | bt_dev_dbg(hdev, "sock %p", sk); | |
74 | ||
75 | return mgmt_cmd_complete(sk, hdev->id, | |
76 | MGMT_OP_READ_DEF_SYSTEM_CONFIG, | |
77 | 0, rp, sizeof(params)); | |
78 | } | |
79 | ||
80 | #define TO_TLV(x) ((struct mgmt_tlv *)(x)) | |
81 | #define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value))) | |
82 | ||
83 | int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, | |
84 | u16 data_len) | |
85 | { | |
86 | u16 buffer_left = data_len; | |
87 | u8 *buffer = data; | |
88 | ||
89 | if (buffer_left < sizeof(struct mgmt_tlv)) { | |
90 | return mgmt_cmd_status(sk, hdev->id, | |
91 | MGMT_OP_SET_DEF_SYSTEM_CONFIG, | |
92 | MGMT_STATUS_INVALID_PARAMS); | |
93 | } | |
94 | ||
95 | /* First pass to validate the tlv */ | |
96 | while (buffer_left >= sizeof(struct mgmt_tlv)) { | |
97 | const u8 len = TO_TLV(buffer)->length; | |
98 | const u16 exp_len = sizeof(struct mgmt_tlv) + | |
99 | len; | |
100 | const u16 type = le16_to_cpu(TO_TLV(buffer)->type); | |
101 | ||
102 | if (buffer_left < exp_len) { | |
103 | bt_dev_warn(hdev, "invalid len left %d, exp >= %d", | |
104 | buffer_left, exp_len); | |
105 | ||
106 | return mgmt_cmd_status(sk, hdev->id, | |
107 | MGMT_OP_SET_DEF_SYSTEM_CONFIG, | |
108 | MGMT_STATUS_INVALID_PARAMS); | |
109 | } | |
110 | ||
111 | /* Please see mgmt-api.txt for documentation of these values */ | |
112 | switch (type) { | |
113 | case 0x0000: | |
114 | case 0x0001: | |
115 | case 0x0002: | |
116 | case 0x0003: | |
117 | case 0x0004: | |
118 | case 0x0005: | |
119 | case 0x0006: | |
120 | case 0x0007: | |
121 | case 0x0008: | |
122 | case 0x0009: | |
123 | case 0x000a: | |
124 | case 0x000b: | |
125 | case 0x000c: | |
126 | case 0x000d: | |
127 | case 0x000e: | |
128 | case 0x000f: | |
129 | case 0x0010: | |
130 | case 0x0011: | |
131 | case 0x0012: | |
132 | case 0x0013: | |
133 | case 0x0014: | |
134 | case 0x0015: | |
135 | case 0x0016: | |
136 | case 0x0017: | |
137 | case 0x0018: | |
138 | case 0x0019: | |
139 | case 0x001a: | |
49b020c1 | 140 | case 0x001b: |
17896406 AM |
141 | if (len != sizeof(u16)) { |
142 | bt_dev_warn(hdev, "invalid length %d, exp %zu for type %d", | |
143 | len, sizeof(u16), type); | |
144 | ||
145 | return mgmt_cmd_status(sk, hdev->id, | |
146 | MGMT_OP_SET_DEF_SYSTEM_CONFIG, | |
147 | MGMT_STATUS_INVALID_PARAMS); | |
148 | } | |
149 | break; | |
150 | default: | |
151 | bt_dev_warn(hdev, "unsupported parameter %u", type); | |
152 | break; | |
153 | } | |
154 | ||
155 | buffer_left -= exp_len; | |
156 | buffer += exp_len; | |
157 | } | |
158 | ||
159 | buffer_left = data_len; | |
160 | buffer = data; | |
161 | while (buffer_left >= sizeof(struct mgmt_tlv)) { | |
162 | const u8 len = TO_TLV(buffer)->length; | |
163 | const u16 exp_len = sizeof(struct mgmt_tlv) + | |
164 | len; | |
165 | const u16 type = le16_to_cpu(TO_TLV(buffer)->type); | |
166 | ||
167 | switch (type) { | |
168 | case 0x0000: | |
169 | hdev->def_page_scan_type = TLV_GET_LE16(buffer); | |
170 | break; | |
171 | case 0x0001: | |
172 | hdev->def_page_scan_int = TLV_GET_LE16(buffer); | |
173 | break; | |
174 | case 0x0002: | |
175 | hdev->def_page_scan_window = TLV_GET_LE16(buffer); | |
176 | break; | |
177 | case 0x0003: | |
178 | hdev->def_inq_scan_type = TLV_GET_LE16(buffer); | |
179 | break; | |
180 | case 0x0004: | |
181 | hdev->def_inq_scan_int = TLV_GET_LE16(buffer); | |
182 | break; | |
183 | case 0x0005: | |
184 | hdev->def_inq_scan_window = TLV_GET_LE16(buffer); | |
185 | break; | |
186 | case 0x0006: | |
187 | hdev->def_br_lsto = TLV_GET_LE16(buffer); | |
188 | break; | |
189 | case 0x0007: | |
190 | hdev->def_page_timeout = TLV_GET_LE16(buffer); | |
191 | break; | |
192 | case 0x0008: | |
193 | hdev->sniff_min_interval = TLV_GET_LE16(buffer); | |
194 | break; | |
195 | case 0x0009: | |
196 | hdev->sniff_max_interval = TLV_GET_LE16(buffer); | |
197 | break; | |
198 | case 0x000a: | |
199 | hdev->le_adv_min_interval = TLV_GET_LE16(buffer); | |
200 | break; | |
201 | case 0x000b: | |
202 | hdev->le_adv_max_interval = TLV_GET_LE16(buffer); | |
203 | break; | |
204 | case 0x000c: | |
205 | hdev->def_multi_adv_rotation_duration = | |
206 | TLV_GET_LE16(buffer); | |
207 | break; | |
208 | case 0x000d: | |
209 | hdev->le_scan_interval = TLV_GET_LE16(buffer); | |
210 | break; | |
211 | case 0x000e: | |
212 | hdev->le_scan_window = TLV_GET_LE16(buffer); | |
213 | break; | |
214 | case 0x000f: | |
215 | hdev->le_scan_int_suspend = TLV_GET_LE16(buffer); | |
216 | break; | |
217 | case 0x0010: | |
218 | hdev->le_scan_window_suspend = TLV_GET_LE16(buffer); | |
219 | break; | |
220 | case 0x0011: | |
221 | hdev->le_scan_int_discovery = TLV_GET_LE16(buffer); | |
222 | break; | |
223 | case 0x00012: | |
224 | hdev->le_scan_window_discovery = TLV_GET_LE16(buffer); | |
225 | break; | |
226 | case 0x00013: | |
227 | hdev->le_scan_int_adv_monitor = TLV_GET_LE16(buffer); | |
228 | break; | |
229 | case 0x00014: | |
230 | hdev->le_scan_window_adv_monitor = TLV_GET_LE16(buffer); | |
231 | break; | |
232 | case 0x00015: | |
233 | hdev->le_scan_int_connect = TLV_GET_LE16(buffer); | |
234 | break; | |
235 | case 0x00016: | |
236 | hdev->le_scan_window_connect = TLV_GET_LE16(buffer); | |
237 | break; | |
238 | case 0x00017: | |
239 | hdev->le_conn_min_interval = TLV_GET_LE16(buffer); | |
240 | break; | |
241 | case 0x00018: | |
242 | hdev->le_conn_max_interval = TLV_GET_LE16(buffer); | |
243 | break; | |
244 | case 0x00019: | |
245 | hdev->le_conn_latency = TLV_GET_LE16(buffer); | |
246 | break; | |
247 | case 0x0001a: | |
248 | hdev->le_supv_timeout = TLV_GET_LE16(buffer); | |
249 | break; | |
49b020c1 AM |
250 | case 0x0001b: |
251 | hdev->def_le_autoconnect_timeout = | |
252 | msecs_to_jiffies(TLV_GET_LE16(buffer)); | |
253 | break; | |
17896406 AM |
254 | default: |
255 | bt_dev_warn(hdev, "unsupported parameter %u", type); | |
256 | break; | |
257 | } | |
258 | ||
259 | buffer_left -= exp_len; | |
260 | buffer += exp_len; | |
261 | } | |
262 | ||
46605a27 MH |
263 | return mgmt_cmd_complete(sk, hdev->id, |
264 | MGMT_OP_SET_DEF_SYSTEM_CONFIG, 0, NULL, 0); | |
17896406 | 265 | } |
aececa64 MH |
266 | |
267 | int read_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data, | |
268 | u16 data_len) | |
269 | { | |
270 | bt_dev_dbg(hdev, "sock %p", sk); | |
271 | ||
272 | return mgmt_cmd_complete(sk, hdev->id, | |
273 | MGMT_OP_READ_DEF_RUNTIME_CONFIG, 0, NULL, 0); | |
274 | } | |
275 | ||
276 | int set_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data, | |
277 | u16 data_len) | |
278 | { | |
279 | bt_dev_dbg(hdev, "sock %p", sk); | |
280 | ||
281 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEF_SYSTEM_CONFIG, | |
282 | MGMT_STATUS_INVALID_PARAMS); | |
283 | } |