Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bluetooth/mgmt_config.c
26278 views
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
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
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
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
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
348