diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-12-20 10:05:16 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2014-12-20 10:51:23 -0500 |
commit | 3a5c82b78fd28ef39c5d07e72c78a569a6ea658a (patch) | |
tree | 017d9c0252a74be5ec71adcdcb55b74a577a4fab /net/bluetooth | |
parent | 71c3b60ec6d288f2551b517186b025da4cbb18b5 (diff) |
Bluetooth: Move LE debugfs file creation into hci_debugfs.c
This patch moves the creation of the debugs files for LE controllers
into hci_debugfs.c file.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_core.c | 478 | ||||
-rw-r--r-- | net/bluetooth/hci_debugfs.c | 474 |
2 files changed, 474 insertions, 478 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d8976cb01b89..2db071b2f0f4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -139,438 +139,6 @@ static const struct file_operations dut_mode_fops = { | |||
139 | .llseek = default_llseek, | 139 | .llseek = default_llseek, |
140 | }; | 140 | }; |
141 | 141 | ||
142 | static int rpa_timeout_set(void *data, u64 val) | ||
143 | { | ||
144 | struct hci_dev *hdev = data; | ||
145 | |||
146 | /* Require the RPA timeout to be at least 30 seconds and at most | ||
147 | * 24 hours. | ||
148 | */ | ||
149 | if (val < 30 || val > (60 * 60 * 24)) | ||
150 | return -EINVAL; | ||
151 | |||
152 | hci_dev_lock(hdev); | ||
153 | hdev->rpa_timeout = val; | ||
154 | hci_dev_unlock(hdev); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int rpa_timeout_get(void *data, u64 *val) | ||
160 | { | ||
161 | struct hci_dev *hdev = data; | ||
162 | |||
163 | hci_dev_lock(hdev); | ||
164 | *val = hdev->rpa_timeout; | ||
165 | hci_dev_unlock(hdev); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | DEFINE_SIMPLE_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get, | ||
171 | rpa_timeout_set, "%llu\n"); | ||
172 | |||
173 | static int identity_show(struct seq_file *f, void *p) | ||
174 | { | ||
175 | struct hci_dev *hdev = f->private; | ||
176 | bdaddr_t addr; | ||
177 | u8 addr_type; | ||
178 | |||
179 | hci_dev_lock(hdev); | ||
180 | |||
181 | hci_copy_identity_address(hdev, &addr, &addr_type); | ||
182 | |||
183 | seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type, | ||
184 | 16, hdev->irk, &hdev->rpa); | ||
185 | |||
186 | hci_dev_unlock(hdev); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int identity_open(struct inode *inode, struct file *file) | ||
192 | { | ||
193 | return single_open(file, identity_show, inode->i_private); | ||
194 | } | ||
195 | |||
196 | static const struct file_operations identity_fops = { | ||
197 | .open = identity_open, | ||
198 | .read = seq_read, | ||
199 | .llseek = seq_lseek, | ||
200 | .release = single_release, | ||
201 | }; | ||
202 | |||
203 | static int random_address_show(struct seq_file *f, void *p) | ||
204 | { | ||
205 | struct hci_dev *hdev = f->private; | ||
206 | |||
207 | hci_dev_lock(hdev); | ||
208 | seq_printf(f, "%pMR\n", &hdev->random_addr); | ||
209 | hci_dev_unlock(hdev); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int random_address_open(struct inode *inode, struct file *file) | ||
215 | { | ||
216 | return single_open(file, random_address_show, inode->i_private); | ||
217 | } | ||
218 | |||
219 | static const struct file_operations random_address_fops = { | ||
220 | .open = random_address_open, | ||
221 | .read = seq_read, | ||
222 | .llseek = seq_lseek, | ||
223 | .release = single_release, | ||
224 | }; | ||
225 | |||
226 | static int static_address_show(struct seq_file *f, void *p) | ||
227 | { | ||
228 | struct hci_dev *hdev = f->private; | ||
229 | |||
230 | hci_dev_lock(hdev); | ||
231 | seq_printf(f, "%pMR\n", &hdev->static_addr); | ||
232 | hci_dev_unlock(hdev); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int static_address_open(struct inode *inode, struct file *file) | ||
238 | { | ||
239 | return single_open(file, static_address_show, inode->i_private); | ||
240 | } | ||
241 | |||
242 | static const struct file_operations static_address_fops = { | ||
243 | .open = static_address_open, | ||
244 | .read = seq_read, | ||
245 | .llseek = seq_lseek, | ||
246 | .release = single_release, | ||
247 | }; | ||
248 | |||
249 | static ssize_t force_static_address_read(struct file *file, | ||
250 | char __user *user_buf, | ||
251 | size_t count, loff_t *ppos) | ||
252 | { | ||
253 | struct hci_dev *hdev = file->private_data; | ||
254 | char buf[3]; | ||
255 | |||
256 | buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ? 'Y': 'N'; | ||
257 | buf[1] = '\n'; | ||
258 | buf[2] = '\0'; | ||
259 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
260 | } | ||
261 | |||
262 | static ssize_t force_static_address_write(struct file *file, | ||
263 | const char __user *user_buf, | ||
264 | size_t count, loff_t *ppos) | ||
265 | { | ||
266 | struct hci_dev *hdev = file->private_data; | ||
267 | char buf[32]; | ||
268 | size_t buf_size = min(count, (sizeof(buf)-1)); | ||
269 | bool enable; | ||
270 | |||
271 | if (test_bit(HCI_UP, &hdev->flags)) | ||
272 | return -EBUSY; | ||
273 | |||
274 | if (copy_from_user(buf, user_buf, buf_size)) | ||
275 | return -EFAULT; | ||
276 | |||
277 | buf[buf_size] = '\0'; | ||
278 | if (strtobool(buf, &enable)) | ||
279 | return -EINVAL; | ||
280 | |||
281 | if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags)) | ||
282 | return -EALREADY; | ||
283 | |||
284 | change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags); | ||
285 | |||
286 | return count; | ||
287 | } | ||
288 | |||
289 | static const struct file_operations force_static_address_fops = { | ||
290 | .open = simple_open, | ||
291 | .read = force_static_address_read, | ||
292 | .write = force_static_address_write, | ||
293 | .llseek = default_llseek, | ||
294 | }; | ||
295 | |||
296 | static int white_list_show(struct seq_file *f, void *ptr) | ||
297 | { | ||
298 | struct hci_dev *hdev = f->private; | ||
299 | struct bdaddr_list *b; | ||
300 | |||
301 | hci_dev_lock(hdev); | ||
302 | list_for_each_entry(b, &hdev->le_white_list, list) | ||
303 | seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); | ||
304 | hci_dev_unlock(hdev); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int white_list_open(struct inode *inode, struct file *file) | ||
310 | { | ||
311 | return single_open(file, white_list_show, inode->i_private); | ||
312 | } | ||
313 | |||
314 | static const struct file_operations white_list_fops = { | ||
315 | .open = white_list_open, | ||
316 | .read = seq_read, | ||
317 | .llseek = seq_lseek, | ||
318 | .release = single_release, | ||
319 | }; | ||
320 | |||
321 | static int identity_resolving_keys_show(struct seq_file *f, void *ptr) | ||
322 | { | ||
323 | struct hci_dev *hdev = f->private; | ||
324 | struct smp_irk *irk; | ||
325 | |||
326 | rcu_read_lock(); | ||
327 | list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) { | ||
328 | seq_printf(f, "%pMR (type %u) %*phN %pMR\n", | ||
329 | &irk->bdaddr, irk->addr_type, | ||
330 | 16, irk->val, &irk->rpa); | ||
331 | } | ||
332 | rcu_read_unlock(); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int identity_resolving_keys_open(struct inode *inode, struct file *file) | ||
338 | { | ||
339 | return single_open(file, identity_resolving_keys_show, | ||
340 | inode->i_private); | ||
341 | } | ||
342 | |||
343 | static const struct file_operations identity_resolving_keys_fops = { | ||
344 | .open = identity_resolving_keys_open, | ||
345 | .read = seq_read, | ||
346 | .llseek = seq_lseek, | ||
347 | .release = single_release, | ||
348 | }; | ||
349 | |||
350 | static int long_term_keys_show(struct seq_file *f, void *ptr) | ||
351 | { | ||
352 | struct hci_dev *hdev = f->private; | ||
353 | struct smp_ltk *ltk; | ||
354 | |||
355 | rcu_read_lock(); | ||
356 | list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list) | ||
357 | seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n", | ||
358 | <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, | ||
359 | ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), | ||
360 | __le64_to_cpu(ltk->rand), 16, ltk->val); | ||
361 | rcu_read_unlock(); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int long_term_keys_open(struct inode *inode, struct file *file) | ||
367 | { | ||
368 | return single_open(file, long_term_keys_show, inode->i_private); | ||
369 | } | ||
370 | |||
371 | static const struct file_operations long_term_keys_fops = { | ||
372 | .open = long_term_keys_open, | ||
373 | .read = seq_read, | ||
374 | .llseek = seq_lseek, | ||
375 | .release = single_release, | ||
376 | }; | ||
377 | |||
378 | static int conn_min_interval_set(void *data, u64 val) | ||
379 | { | ||
380 | struct hci_dev *hdev = data; | ||
381 | |||
382 | if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) | ||
383 | return -EINVAL; | ||
384 | |||
385 | hci_dev_lock(hdev); | ||
386 | hdev->le_conn_min_interval = val; | ||
387 | hci_dev_unlock(hdev); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int conn_min_interval_get(void *data, u64 *val) | ||
393 | { | ||
394 | struct hci_dev *hdev = data; | ||
395 | |||
396 | hci_dev_lock(hdev); | ||
397 | *val = hdev->le_conn_min_interval; | ||
398 | hci_dev_unlock(hdev); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | DEFINE_SIMPLE_ATTRIBUTE(conn_min_interval_fops, conn_min_interval_get, | ||
404 | conn_min_interval_set, "%llu\n"); | ||
405 | |||
406 | static int conn_max_interval_set(void *data, u64 val) | ||
407 | { | ||
408 | struct hci_dev *hdev = data; | ||
409 | |||
410 | if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) | ||
411 | return -EINVAL; | ||
412 | |||
413 | hci_dev_lock(hdev); | ||
414 | hdev->le_conn_max_interval = val; | ||
415 | hci_dev_unlock(hdev); | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int conn_max_interval_get(void *data, u64 *val) | ||
421 | { | ||
422 | struct hci_dev *hdev = data; | ||
423 | |||
424 | hci_dev_lock(hdev); | ||
425 | *val = hdev->le_conn_max_interval; | ||
426 | hci_dev_unlock(hdev); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, | ||
432 | conn_max_interval_set, "%llu\n"); | ||
433 | |||
434 | static int conn_latency_set(void *data, u64 val) | ||
435 | { | ||
436 | struct hci_dev *hdev = data; | ||
437 | |||
438 | if (val > 0x01f3) | ||
439 | return -EINVAL; | ||
440 | |||
441 | hci_dev_lock(hdev); | ||
442 | hdev->le_conn_latency = val; | ||
443 | hci_dev_unlock(hdev); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int conn_latency_get(void *data, u64 *val) | ||
449 | { | ||
450 | struct hci_dev *hdev = data; | ||
451 | |||
452 | hci_dev_lock(hdev); | ||
453 | *val = hdev->le_conn_latency; | ||
454 | hci_dev_unlock(hdev); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | DEFINE_SIMPLE_ATTRIBUTE(conn_latency_fops, conn_latency_get, | ||
460 | conn_latency_set, "%llu\n"); | ||
461 | |||
462 | static int supervision_timeout_set(void *data, u64 val) | ||
463 | { | ||
464 | struct hci_dev *hdev = data; | ||
465 | |||
466 | if (val < 0x000a || val > 0x0c80) | ||
467 | return -EINVAL; | ||
468 | |||
469 | hci_dev_lock(hdev); | ||
470 | hdev->le_supv_timeout = val; | ||
471 | hci_dev_unlock(hdev); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int supervision_timeout_get(void *data, u64 *val) | ||
477 | { | ||
478 | struct hci_dev *hdev = data; | ||
479 | |||
480 | hci_dev_lock(hdev); | ||
481 | *val = hdev->le_supv_timeout; | ||
482 | hci_dev_unlock(hdev); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | DEFINE_SIMPLE_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, | ||
488 | supervision_timeout_set, "%llu\n"); | ||
489 | |||
490 | static int adv_channel_map_set(void *data, u64 val) | ||
491 | { | ||
492 | struct hci_dev *hdev = data; | ||
493 | |||
494 | if (val < 0x01 || val > 0x07) | ||
495 | return -EINVAL; | ||
496 | |||
497 | hci_dev_lock(hdev); | ||
498 | hdev->le_adv_channel_map = val; | ||
499 | hci_dev_unlock(hdev); | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | static int adv_channel_map_get(void *data, u64 *val) | ||
505 | { | ||
506 | struct hci_dev *hdev = data; | ||
507 | |||
508 | hci_dev_lock(hdev); | ||
509 | *val = hdev->le_adv_channel_map; | ||
510 | hci_dev_unlock(hdev); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, | ||
516 | adv_channel_map_set, "%llu\n"); | ||
517 | |||
518 | static int adv_min_interval_set(void *data, u64 val) | ||
519 | { | ||
520 | struct hci_dev *hdev = data; | ||
521 | |||
522 | if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) | ||
523 | return -EINVAL; | ||
524 | |||
525 | hci_dev_lock(hdev); | ||
526 | hdev->le_adv_min_interval = val; | ||
527 | hci_dev_unlock(hdev); | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int adv_min_interval_get(void *data, u64 *val) | ||
533 | { | ||
534 | struct hci_dev *hdev = data; | ||
535 | |||
536 | hci_dev_lock(hdev); | ||
537 | *val = hdev->le_adv_min_interval; | ||
538 | hci_dev_unlock(hdev); | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, | ||
544 | adv_min_interval_set, "%llu\n"); | ||
545 | |||
546 | static int adv_max_interval_set(void *data, u64 val) | ||
547 | { | ||
548 | struct hci_dev *hdev = data; | ||
549 | |||
550 | if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) | ||
551 | return -EINVAL; | ||
552 | |||
553 | hci_dev_lock(hdev); | ||
554 | hdev->le_adv_max_interval = val; | ||
555 | hci_dev_unlock(hdev); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int adv_max_interval_get(void *data, u64 *val) | ||
561 | { | ||
562 | struct hci_dev *hdev = data; | ||
563 | |||
564 | hci_dev_lock(hdev); | ||
565 | *val = hdev->le_adv_max_interval; | ||
566 | hci_dev_unlock(hdev); | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, | ||
572 | adv_max_interval_set, "%llu\n"); | ||
573 | |||
574 | /* ---- HCI requests ---- */ | 142 | /* ---- HCI requests ---- */ |
575 | 143 | ||
576 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) | 144 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) |
@@ -1355,53 +923,7 @@ static int __hci_init(struct hci_dev *hdev) | |||
1355 | hci_debugfs_create_bredr(hdev); | 923 | hci_debugfs_create_bredr(hdev); |
1356 | 924 | ||
1357 | if (lmp_le_capable(hdev)) { | 925 | if (lmp_le_capable(hdev)) { |
1358 | debugfs_create_file("identity", 0400, hdev->debugfs, | ||
1359 | hdev, &identity_fops); | ||
1360 | debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, | ||
1361 | hdev, &rpa_timeout_fops); | ||
1362 | debugfs_create_file("random_address", 0444, hdev->debugfs, | ||
1363 | hdev, &random_address_fops); | ||
1364 | debugfs_create_file("static_address", 0444, hdev->debugfs, | ||
1365 | hdev, &static_address_fops); | ||
1366 | |||
1367 | /* For controllers with a public address, provide a debug | ||
1368 | * option to force the usage of the configured static | ||
1369 | * address. By default the public address is used. | ||
1370 | */ | ||
1371 | if (bacmp(&hdev->bdaddr, BDADDR_ANY)) | ||
1372 | debugfs_create_file("force_static_address", 0644, | ||
1373 | hdev->debugfs, hdev, | ||
1374 | &force_static_address_fops); | ||
1375 | |||
1376 | debugfs_create_u8("white_list_size", 0444, hdev->debugfs, | ||
1377 | &hdev->le_white_list_size); | ||
1378 | debugfs_create_file("white_list", 0444, hdev->debugfs, hdev, | ||
1379 | &white_list_fops); | ||
1380 | debugfs_create_file("identity_resolving_keys", 0400, | ||
1381 | hdev->debugfs, hdev, | ||
1382 | &identity_resolving_keys_fops); | ||
1383 | debugfs_create_file("long_term_keys", 0400, hdev->debugfs, | ||
1384 | hdev, &long_term_keys_fops); | ||
1385 | debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, | ||
1386 | hdev, &conn_min_interval_fops); | ||
1387 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, | ||
1388 | hdev, &conn_max_interval_fops); | ||
1389 | debugfs_create_file("conn_latency", 0644, hdev->debugfs, | ||
1390 | hdev, &conn_latency_fops); | ||
1391 | debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, | ||
1392 | hdev, &supervision_timeout_fops); | ||
1393 | debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, | ||
1394 | hdev, &adv_channel_map_fops); | ||
1395 | debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, | ||
1396 | hdev, &adv_min_interval_fops); | ||
1397 | debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, | ||
1398 | hdev, &adv_max_interval_fops); | ||
1399 | debugfs_create_u16("discov_interleaved_timeout", 0644, | ||
1400 | hdev->debugfs, | ||
1401 | &hdev->discov_interleaved_timeout); | ||
1402 | |||
1403 | hci_debugfs_create_le(hdev); | 926 | hci_debugfs_create_le(hdev); |
1404 | |||
1405 | smp_register(hdev); | 927 | smp_register(hdev); |
1406 | } | 928 | } |
1407 | 929 | ||
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 435f091301cd..a7a0db03b0b8 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c | |||
@@ -585,6 +585,480 @@ void hci_debugfs_create_bredr(struct hci_dev *hdev) | |||
585 | } | 585 | } |
586 | } | 586 | } |
587 | 587 | ||
588 | static int identity_show(struct seq_file *f, void *p) | ||
589 | { | ||
590 | struct hci_dev *hdev = f->private; | ||
591 | bdaddr_t addr; | ||
592 | u8 addr_type; | ||
593 | |||
594 | hci_dev_lock(hdev); | ||
595 | |||
596 | hci_copy_identity_address(hdev, &addr, &addr_type); | ||
597 | |||
598 | seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type, | ||
599 | 16, hdev->irk, &hdev->rpa); | ||
600 | |||
601 | hci_dev_unlock(hdev); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int identity_open(struct inode *inode, struct file *file) | ||
607 | { | ||
608 | return single_open(file, identity_show, inode->i_private); | ||
609 | } | ||
610 | |||
611 | static const struct file_operations identity_fops = { | ||
612 | .open = identity_open, | ||
613 | .read = seq_read, | ||
614 | .llseek = seq_lseek, | ||
615 | .release = single_release, | ||
616 | }; | ||
617 | |||
618 | static int rpa_timeout_set(void *data, u64 val) | ||
619 | { | ||
620 | struct hci_dev *hdev = data; | ||
621 | |||
622 | /* Require the RPA timeout to be at least 30 seconds and at most | ||
623 | * 24 hours. | ||
624 | */ | ||
625 | if (val < 30 || val > (60 * 60 * 24)) | ||
626 | return -EINVAL; | ||
627 | |||
628 | hci_dev_lock(hdev); | ||
629 | hdev->rpa_timeout = val; | ||
630 | hci_dev_unlock(hdev); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int rpa_timeout_get(void *data, u64 *val) | ||
636 | { | ||
637 | struct hci_dev *hdev = data; | ||
638 | |||
639 | hci_dev_lock(hdev); | ||
640 | *val = hdev->rpa_timeout; | ||
641 | hci_dev_unlock(hdev); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | DEFINE_SIMPLE_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get, | ||
647 | rpa_timeout_set, "%llu\n"); | ||
648 | |||
649 | static int random_address_show(struct seq_file *f, void *p) | ||
650 | { | ||
651 | struct hci_dev *hdev = f->private; | ||
652 | |||
653 | hci_dev_lock(hdev); | ||
654 | seq_printf(f, "%pMR\n", &hdev->random_addr); | ||
655 | hci_dev_unlock(hdev); | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int random_address_open(struct inode *inode, struct file *file) | ||
661 | { | ||
662 | return single_open(file, random_address_show, inode->i_private); | ||
663 | } | ||
664 | |||
665 | static const struct file_operations random_address_fops = { | ||
666 | .open = random_address_open, | ||
667 | .read = seq_read, | ||
668 | .llseek = seq_lseek, | ||
669 | .release = single_release, | ||
670 | }; | ||
671 | |||
672 | static int static_address_show(struct seq_file *f, void *p) | ||
673 | { | ||
674 | struct hci_dev *hdev = f->private; | ||
675 | |||
676 | hci_dev_lock(hdev); | ||
677 | seq_printf(f, "%pMR\n", &hdev->static_addr); | ||
678 | hci_dev_unlock(hdev); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int static_address_open(struct inode *inode, struct file *file) | ||
684 | { | ||
685 | return single_open(file, static_address_show, inode->i_private); | ||
686 | } | ||
687 | |||
688 | static const struct file_operations static_address_fops = { | ||
689 | .open = static_address_open, | ||
690 | .read = seq_read, | ||
691 | .llseek = seq_lseek, | ||
692 | .release = single_release, | ||
693 | }; | ||
694 | |||
695 | static ssize_t force_static_address_read(struct file *file, | ||
696 | char __user *user_buf, | ||
697 | size_t count, loff_t *ppos) | ||
698 | { | ||
699 | struct hci_dev *hdev = file->private_data; | ||
700 | char buf[3]; | ||
701 | |||
702 | buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ? 'Y': 'N'; | ||
703 | buf[1] = '\n'; | ||
704 | buf[2] = '\0'; | ||
705 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
706 | } | ||
707 | |||
708 | static ssize_t force_static_address_write(struct file *file, | ||
709 | const char __user *user_buf, | ||
710 | size_t count, loff_t *ppos) | ||
711 | { | ||
712 | struct hci_dev *hdev = file->private_data; | ||
713 | char buf[32]; | ||
714 | size_t buf_size = min(count, (sizeof(buf)-1)); | ||
715 | bool enable; | ||
716 | |||
717 | if (test_bit(HCI_UP, &hdev->flags)) | ||
718 | return -EBUSY; | ||
719 | |||
720 | if (copy_from_user(buf, user_buf, buf_size)) | ||
721 | return -EFAULT; | ||
722 | |||
723 | buf[buf_size] = '\0'; | ||
724 | if (strtobool(buf, &enable)) | ||
725 | return -EINVAL; | ||
726 | |||
727 | if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags)) | ||
728 | return -EALREADY; | ||
729 | |||
730 | change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags); | ||
731 | |||
732 | return count; | ||
733 | } | ||
734 | |||
735 | static const struct file_operations force_static_address_fops = { | ||
736 | .open = simple_open, | ||
737 | .read = force_static_address_read, | ||
738 | .write = force_static_address_write, | ||
739 | .llseek = default_llseek, | ||
740 | }; | ||
741 | |||
742 | static int white_list_show(struct seq_file *f, void *ptr) | ||
743 | { | ||
744 | struct hci_dev *hdev = f->private; | ||
745 | struct bdaddr_list *b; | ||
746 | |||
747 | hci_dev_lock(hdev); | ||
748 | list_for_each_entry(b, &hdev->le_white_list, list) | ||
749 | seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); | ||
750 | hci_dev_unlock(hdev); | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static int white_list_open(struct inode *inode, struct file *file) | ||
756 | { | ||
757 | return single_open(file, white_list_show, inode->i_private); | ||
758 | } | ||
759 | |||
760 | static const struct file_operations white_list_fops = { | ||
761 | .open = white_list_open, | ||
762 | .read = seq_read, | ||
763 | .llseek = seq_lseek, | ||
764 | .release = single_release, | ||
765 | }; | ||
766 | |||
767 | static int identity_resolving_keys_show(struct seq_file *f, void *ptr) | ||
768 | { | ||
769 | struct hci_dev *hdev = f->private; | ||
770 | struct smp_irk *irk; | ||
771 | |||
772 | rcu_read_lock(); | ||
773 | list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) { | ||
774 | seq_printf(f, "%pMR (type %u) %*phN %pMR\n", | ||
775 | &irk->bdaddr, irk->addr_type, | ||
776 | 16, irk->val, &irk->rpa); | ||
777 | } | ||
778 | rcu_read_unlock(); | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int identity_resolving_keys_open(struct inode *inode, struct file *file) | ||
784 | { | ||
785 | return single_open(file, identity_resolving_keys_show, | ||
786 | inode->i_private); | ||
787 | } | ||
788 | |||
789 | static const struct file_operations identity_resolving_keys_fops = { | ||
790 | .open = identity_resolving_keys_open, | ||
791 | .read = seq_read, | ||
792 | .llseek = seq_lseek, | ||
793 | .release = single_release, | ||
794 | }; | ||
795 | |||
796 | static int long_term_keys_show(struct seq_file *f, void *ptr) | ||
797 | { | ||
798 | struct hci_dev *hdev = f->private; | ||
799 | struct smp_ltk *ltk; | ||
800 | |||
801 | rcu_read_lock(); | ||
802 | list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list) | ||
803 | seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n", | ||
804 | <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, | ||
805 | ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), | ||
806 | __le64_to_cpu(ltk->rand), 16, ltk->val); | ||
807 | rcu_read_unlock(); | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int long_term_keys_open(struct inode *inode, struct file *file) | ||
813 | { | ||
814 | return single_open(file, long_term_keys_show, inode->i_private); | ||
815 | } | ||
816 | |||
817 | static const struct file_operations long_term_keys_fops = { | ||
818 | .open = long_term_keys_open, | ||
819 | .read = seq_read, | ||
820 | .llseek = seq_lseek, | ||
821 | .release = single_release, | ||
822 | }; | ||
823 | |||
824 | static int conn_min_interval_set(void *data, u64 val) | ||
825 | { | ||
826 | struct hci_dev *hdev = data; | ||
827 | |||
828 | if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) | ||
829 | return -EINVAL; | ||
830 | |||
831 | hci_dev_lock(hdev); | ||
832 | hdev->le_conn_min_interval = val; | ||
833 | hci_dev_unlock(hdev); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int conn_min_interval_get(void *data, u64 *val) | ||
839 | { | ||
840 | struct hci_dev *hdev = data; | ||
841 | |||
842 | hci_dev_lock(hdev); | ||
843 | *val = hdev->le_conn_min_interval; | ||
844 | hci_dev_unlock(hdev); | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | DEFINE_SIMPLE_ATTRIBUTE(conn_min_interval_fops, conn_min_interval_get, | ||
850 | conn_min_interval_set, "%llu\n"); | ||
851 | |||
852 | static int conn_max_interval_set(void *data, u64 val) | ||
853 | { | ||
854 | struct hci_dev *hdev = data; | ||
855 | |||
856 | if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) | ||
857 | return -EINVAL; | ||
858 | |||
859 | hci_dev_lock(hdev); | ||
860 | hdev->le_conn_max_interval = val; | ||
861 | hci_dev_unlock(hdev); | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static int conn_max_interval_get(void *data, u64 *val) | ||
867 | { | ||
868 | struct hci_dev *hdev = data; | ||
869 | |||
870 | hci_dev_lock(hdev); | ||
871 | *val = hdev->le_conn_max_interval; | ||
872 | hci_dev_unlock(hdev); | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, | ||
878 | conn_max_interval_set, "%llu\n"); | ||
879 | |||
880 | static int conn_latency_set(void *data, u64 val) | ||
881 | { | ||
882 | struct hci_dev *hdev = data; | ||
883 | |||
884 | if (val > 0x01f3) | ||
885 | return -EINVAL; | ||
886 | |||
887 | hci_dev_lock(hdev); | ||
888 | hdev->le_conn_latency = val; | ||
889 | hci_dev_unlock(hdev); | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int conn_latency_get(void *data, u64 *val) | ||
895 | { | ||
896 | struct hci_dev *hdev = data; | ||
897 | |||
898 | hci_dev_lock(hdev); | ||
899 | *val = hdev->le_conn_latency; | ||
900 | hci_dev_unlock(hdev); | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | DEFINE_SIMPLE_ATTRIBUTE(conn_latency_fops, conn_latency_get, | ||
906 | conn_latency_set, "%llu\n"); | ||
907 | |||
908 | static int supervision_timeout_set(void *data, u64 val) | ||
909 | { | ||
910 | struct hci_dev *hdev = data; | ||
911 | |||
912 | if (val < 0x000a || val > 0x0c80) | ||
913 | return -EINVAL; | ||
914 | |||
915 | hci_dev_lock(hdev); | ||
916 | hdev->le_supv_timeout = val; | ||
917 | hci_dev_unlock(hdev); | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int supervision_timeout_get(void *data, u64 *val) | ||
923 | { | ||
924 | struct hci_dev *hdev = data; | ||
925 | |||
926 | hci_dev_lock(hdev); | ||
927 | *val = hdev->le_supv_timeout; | ||
928 | hci_dev_unlock(hdev); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | DEFINE_SIMPLE_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, | ||
934 | supervision_timeout_set, "%llu\n"); | ||
935 | |||
936 | static int adv_channel_map_set(void *data, u64 val) | ||
937 | { | ||
938 | struct hci_dev *hdev = data; | ||
939 | |||
940 | if (val < 0x01 || val > 0x07) | ||
941 | return -EINVAL; | ||
942 | |||
943 | hci_dev_lock(hdev); | ||
944 | hdev->le_adv_channel_map = val; | ||
945 | hci_dev_unlock(hdev); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int adv_channel_map_get(void *data, u64 *val) | ||
951 | { | ||
952 | struct hci_dev *hdev = data; | ||
953 | |||
954 | hci_dev_lock(hdev); | ||
955 | *val = hdev->le_adv_channel_map; | ||
956 | hci_dev_unlock(hdev); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, | ||
962 | adv_channel_map_set, "%llu\n"); | ||
963 | |||
964 | static int adv_min_interval_set(void *data, u64 val) | ||
965 | { | ||
966 | struct hci_dev *hdev = data; | ||
967 | |||
968 | if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) | ||
969 | return -EINVAL; | ||
970 | |||
971 | hci_dev_lock(hdev); | ||
972 | hdev->le_adv_min_interval = val; | ||
973 | hci_dev_unlock(hdev); | ||
974 | |||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | static int adv_min_interval_get(void *data, u64 *val) | ||
979 | { | ||
980 | struct hci_dev *hdev = data; | ||
981 | |||
982 | hci_dev_lock(hdev); | ||
983 | *val = hdev->le_adv_min_interval; | ||
984 | hci_dev_unlock(hdev); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, | ||
990 | adv_min_interval_set, "%llu\n"); | ||
991 | |||
992 | static int adv_max_interval_set(void *data, u64 val) | ||
993 | { | ||
994 | struct hci_dev *hdev = data; | ||
995 | |||
996 | if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) | ||
997 | return -EINVAL; | ||
998 | |||
999 | hci_dev_lock(hdev); | ||
1000 | hdev->le_adv_max_interval = val; | ||
1001 | hci_dev_unlock(hdev); | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int adv_max_interval_get(void *data, u64 *val) | ||
1007 | { | ||
1008 | struct hci_dev *hdev = data; | ||
1009 | |||
1010 | hci_dev_lock(hdev); | ||
1011 | *val = hdev->le_adv_max_interval; | ||
1012 | hci_dev_unlock(hdev); | ||
1013 | |||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, | ||
1018 | adv_max_interval_set, "%llu\n"); | ||
1019 | |||
588 | void hci_debugfs_create_le(struct hci_dev *hdev) | 1020 | void hci_debugfs_create_le(struct hci_dev *hdev) |
589 | { | 1021 | { |
1022 | debugfs_create_file("identity", 0400, hdev->debugfs, hdev, | ||
1023 | &identity_fops); | ||
1024 | debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, hdev, | ||
1025 | &rpa_timeout_fops); | ||
1026 | debugfs_create_file("random_address", 0444, hdev->debugfs, hdev, | ||
1027 | &random_address_fops); | ||
1028 | debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, | ||
1029 | &static_address_fops); | ||
1030 | |||
1031 | /* For controllers with a public address, provide a debug | ||
1032 | * option to force the usage of the configured static | ||
1033 | * address. By default the public address is used. | ||
1034 | */ | ||
1035 | if (bacmp(&hdev->bdaddr, BDADDR_ANY)) | ||
1036 | debugfs_create_file("force_static_address", 0644, | ||
1037 | hdev->debugfs, hdev, | ||
1038 | &force_static_address_fops); | ||
1039 | |||
1040 | debugfs_create_u8("white_list_size", 0444, hdev->debugfs, | ||
1041 | &hdev->le_white_list_size); | ||
1042 | debugfs_create_file("white_list", 0444, hdev->debugfs, hdev, | ||
1043 | &white_list_fops); | ||
1044 | debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs, | ||
1045 | hdev, &identity_resolving_keys_fops); | ||
1046 | debugfs_create_file("long_term_keys", 0400, hdev->debugfs, hdev, | ||
1047 | &long_term_keys_fops); | ||
1048 | debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, hdev, | ||
1049 | &conn_min_interval_fops); | ||
1050 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, | ||
1051 | &conn_max_interval_fops); | ||
1052 | debugfs_create_file("conn_latency", 0644, hdev->debugfs, hdev, | ||
1053 | &conn_latency_fops); | ||
1054 | debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, hdev, | ||
1055 | &supervision_timeout_fops); | ||
1056 | debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, | ||
1057 | &adv_channel_map_fops); | ||
1058 | debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, hdev, | ||
1059 | &adv_min_interval_fops); | ||
1060 | debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, hdev, | ||
1061 | &adv_max_interval_fops); | ||
1062 | debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, | ||
1063 | &hdev->discov_interleaved_timeout); | ||
590 | } | 1064 | } |