160c5f5fbSMarcel Holtmann /*
260c5f5fbSMarcel Holtmann BlueZ - Bluetooth protocol stack for Linux
360c5f5fbSMarcel Holtmann
460c5f5fbSMarcel Holtmann Copyright (C) 2014 Intel Corporation
560c5f5fbSMarcel Holtmann
660c5f5fbSMarcel Holtmann This program is free software; you can redistribute it and/or modify
760c5f5fbSMarcel Holtmann it under the terms of the GNU General Public License version 2 as
860c5f5fbSMarcel Holtmann published by the Free Software Foundation;
960c5f5fbSMarcel Holtmann
1060c5f5fbSMarcel Holtmann THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1160c5f5fbSMarcel Holtmann OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1260c5f5fbSMarcel Holtmann FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
1360c5f5fbSMarcel Holtmann IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
1460c5f5fbSMarcel Holtmann CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
1560c5f5fbSMarcel Holtmann WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1660c5f5fbSMarcel Holtmann ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1760c5f5fbSMarcel Holtmann OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1860c5f5fbSMarcel Holtmann
1960c5f5fbSMarcel Holtmann ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
2060c5f5fbSMarcel Holtmann COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
2160c5f5fbSMarcel Holtmann SOFTWARE IS DISCLAIMED.
2260c5f5fbSMarcel Holtmann */
2360c5f5fbSMarcel Holtmann
2460c5f5fbSMarcel Holtmann #include <linux/debugfs.h>
2582eae9dcSChristophe JAILLET #include <linux/kstrtox.h>
2660c5f5fbSMarcel Holtmann
2760c5f5fbSMarcel Holtmann #include <net/bluetooth/bluetooth.h>
2860c5f5fbSMarcel Holtmann #include <net/bluetooth/hci_core.h>
2960c5f5fbSMarcel Holtmann
3018f81241SMarcel Holtmann #include "smp.h"
318331dc48SLuiz Augusto von Dentz #include "hci_request.h"
3260c5f5fbSMarcel Holtmann #include "hci_debugfs.h"
3360c5f5fbSMarcel Holtmann
34b55d1abfSJakub Pawlowski #define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \
35b55d1abfSJakub Pawlowski static ssize_t __name ## _read(struct file *file, \
36b55d1abfSJakub Pawlowski char __user *user_buf, \
37b55d1abfSJakub Pawlowski size_t count, loff_t *ppos) \
38b55d1abfSJakub Pawlowski { \
39b55d1abfSJakub Pawlowski struct hci_dev *hdev = file->private_data; \
40b55d1abfSJakub Pawlowski char buf[3]; \
41b55d1abfSJakub Pawlowski \
42b55d1abfSJakub Pawlowski buf[0] = test_bit(__quirk, &hdev->quirks) ? 'Y' : 'N'; \
43b55d1abfSJakub Pawlowski buf[1] = '\n'; \
44b55d1abfSJakub Pawlowski buf[2] = '\0'; \
45b55d1abfSJakub Pawlowski return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \
46b55d1abfSJakub Pawlowski } \
47b55d1abfSJakub Pawlowski \
48b55d1abfSJakub Pawlowski static ssize_t __name ## _write(struct file *file, \
49b55d1abfSJakub Pawlowski const char __user *user_buf, \
50b55d1abfSJakub Pawlowski size_t count, loff_t *ppos) \
51b55d1abfSJakub Pawlowski { \
52b55d1abfSJakub Pawlowski struct hci_dev *hdev = file->private_data; \
53b55d1abfSJakub Pawlowski bool enable; \
543bf5e97dSAndy Shevchenko int err; \
55b55d1abfSJakub Pawlowski \
56b55d1abfSJakub Pawlowski if (test_bit(HCI_UP, &hdev->flags)) \
57b55d1abfSJakub Pawlowski return -EBUSY; \
58b55d1abfSJakub Pawlowski \
593bf5e97dSAndy Shevchenko err = kstrtobool_from_user(user_buf, count, &enable); \
603bf5e97dSAndy Shevchenko if (err) \
613bf5e97dSAndy Shevchenko return err; \
62b55d1abfSJakub Pawlowski \
63b55d1abfSJakub Pawlowski if (enable == test_bit(__quirk, &hdev->quirks)) \
64b55d1abfSJakub Pawlowski return -EALREADY; \
65b55d1abfSJakub Pawlowski \
66b55d1abfSJakub Pawlowski change_bit(__quirk, &hdev->quirks); \
67b55d1abfSJakub Pawlowski \
68b55d1abfSJakub Pawlowski return count; \
69b55d1abfSJakub Pawlowski } \
70b55d1abfSJakub Pawlowski \
71b55d1abfSJakub Pawlowski static const struct file_operations __name ## _fops = { \
72b55d1abfSJakub Pawlowski .open = simple_open, \
73b55d1abfSJakub Pawlowski .read = __name ## _read, \
74b55d1abfSJakub Pawlowski .write = __name ## _write, \
75b55d1abfSJakub Pawlowski .llseek = default_llseek, \
76b55d1abfSJakub Pawlowski } \
77b55d1abfSJakub Pawlowski
785177a838SMarcel Holtmann #define DEFINE_INFO_ATTRIBUTE(__name, __field) \
795177a838SMarcel Holtmann static int __name ## _show(struct seq_file *f, void *ptr) \
805177a838SMarcel Holtmann { \
815177a838SMarcel Holtmann struct hci_dev *hdev = f->private; \
825177a838SMarcel Holtmann \
835177a838SMarcel Holtmann hci_dev_lock(hdev); \
845177a838SMarcel Holtmann seq_printf(f, "%s\n", hdev->__field ? : ""); \
855177a838SMarcel Holtmann hci_dev_unlock(hdev); \
865177a838SMarcel Holtmann \
875177a838SMarcel Holtmann return 0; \
885177a838SMarcel Holtmann } \
895177a838SMarcel Holtmann \
9022b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(__name)
9122b371cbSAndy Shevchenko
features_show(struct seq_file * f,void * ptr)9240ce72b1SMarcel Holtmann static int features_show(struct seq_file *f, void *ptr)
9340ce72b1SMarcel Holtmann {
9440ce72b1SMarcel Holtmann struct hci_dev *hdev = f->private;
9540ce72b1SMarcel Holtmann u8 p;
9640ce72b1SMarcel Holtmann
9740ce72b1SMarcel Holtmann hci_dev_lock(hdev);
988a950794SAndy Shevchenko for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++)
998a950794SAndy Shevchenko seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]);
10040ce72b1SMarcel Holtmann if (lmp_le_capable(hdev))
1018a950794SAndy Shevchenko seq_printf(f, "LE: %8ph\n", hdev->le_features);
10240ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
10340ce72b1SMarcel Holtmann
10440ce72b1SMarcel Holtmann return 0;
10540ce72b1SMarcel Holtmann }
10640ce72b1SMarcel Holtmann
10722b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(features);
10840ce72b1SMarcel Holtmann
device_id_show(struct seq_file * f,void * ptr)109c3370de6SMarcel Holtmann static int device_id_show(struct seq_file *f, void *ptr)
110c3370de6SMarcel Holtmann {
111c3370de6SMarcel Holtmann struct hci_dev *hdev = f->private;
112c3370de6SMarcel Holtmann
113c3370de6SMarcel Holtmann hci_dev_lock(hdev);
114c3370de6SMarcel Holtmann seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source,
115c3370de6SMarcel Holtmann hdev->devid_vendor, hdev->devid_product, hdev->devid_version);
116c3370de6SMarcel Holtmann hci_dev_unlock(hdev);
117c3370de6SMarcel Holtmann
118c3370de6SMarcel Holtmann return 0;
119c3370de6SMarcel Holtmann }
120c3370de6SMarcel Holtmann
12122b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(device_id);
122c3370de6SMarcel Holtmann
device_list_show(struct seq_file * f,void * ptr)12340ce72b1SMarcel Holtmann static int device_list_show(struct seq_file *f, void *ptr)
12440ce72b1SMarcel Holtmann {
12540ce72b1SMarcel Holtmann struct hci_dev *hdev = f->private;
12640ce72b1SMarcel Holtmann struct hci_conn_params *p;
12740ce72b1SMarcel Holtmann struct bdaddr_list *b;
12840ce72b1SMarcel Holtmann
12940ce72b1SMarcel Holtmann hci_dev_lock(hdev);
1303d4f9c00SArchie Pusaka list_for_each_entry(b, &hdev->accept_list, list)
13140ce72b1SMarcel Holtmann seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
13240ce72b1SMarcel Holtmann list_for_each_entry(p, &hdev->le_conn_params, list) {
13340ce72b1SMarcel Holtmann seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type,
13440ce72b1SMarcel Holtmann p->auto_connect);
13540ce72b1SMarcel Holtmann }
13640ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
13740ce72b1SMarcel Holtmann
13840ce72b1SMarcel Holtmann return 0;
13940ce72b1SMarcel Holtmann }
14040ce72b1SMarcel Holtmann
14122b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(device_list);
14240ce72b1SMarcel Holtmann
blacklist_show(struct seq_file * f,void * p)14340ce72b1SMarcel Holtmann static int blacklist_show(struct seq_file *f, void *p)
14440ce72b1SMarcel Holtmann {
14540ce72b1SMarcel Holtmann struct hci_dev *hdev = f->private;
14640ce72b1SMarcel Holtmann struct bdaddr_list *b;
14740ce72b1SMarcel Holtmann
14840ce72b1SMarcel Holtmann hci_dev_lock(hdev);
1493d4f9c00SArchie Pusaka list_for_each_entry(b, &hdev->reject_list, list)
15040ce72b1SMarcel Holtmann seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
15140ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
15240ce72b1SMarcel Holtmann
15340ce72b1SMarcel Holtmann return 0;
15440ce72b1SMarcel Holtmann }
15540ce72b1SMarcel Holtmann
15622b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(blacklist);
15740ce72b1SMarcel Holtmann
blocked_keys_show(struct seq_file * f,void * p)158600a8749SAlain Michaud static int blocked_keys_show(struct seq_file *f, void *p)
159600a8749SAlain Michaud {
160600a8749SAlain Michaud struct hci_dev *hdev = f->private;
161600a8749SAlain Michaud struct blocked_key *key;
162600a8749SAlain Michaud
163600a8749SAlain Michaud rcu_read_lock();
164600a8749SAlain Michaud list_for_each_entry_rcu(key, &hdev->blocked_keys, list)
165600a8749SAlain Michaud seq_printf(f, "%u %*phN\n", key->type, 16, key->val);
166600a8749SAlain Michaud rcu_read_unlock();
167600a8749SAlain Michaud
168600a8749SAlain Michaud return 0;
169600a8749SAlain Michaud }
170600a8749SAlain Michaud
171600a8749SAlain Michaud DEFINE_SHOW_ATTRIBUTE(blocked_keys);
172600a8749SAlain Michaud
uuids_show(struct seq_file * f,void * p)17340ce72b1SMarcel Holtmann static int uuids_show(struct seq_file *f, void *p)
17440ce72b1SMarcel Holtmann {
17540ce72b1SMarcel Holtmann struct hci_dev *hdev = f->private;
17640ce72b1SMarcel Holtmann struct bt_uuid *uuid;
17740ce72b1SMarcel Holtmann
17840ce72b1SMarcel Holtmann hci_dev_lock(hdev);
17940ce72b1SMarcel Holtmann list_for_each_entry(uuid, &hdev->uuids, list) {
18040ce72b1SMarcel Holtmann u8 i, val[16];
18140ce72b1SMarcel Holtmann
18240ce72b1SMarcel Holtmann /* The Bluetooth UUID values are stored in big endian,
18340ce72b1SMarcel Holtmann * but with reversed byte order. So convert them into
18440ce72b1SMarcel Holtmann * the right order for the %pUb modifier.
18540ce72b1SMarcel Holtmann */
18640ce72b1SMarcel Holtmann for (i = 0; i < 16; i++)
18740ce72b1SMarcel Holtmann val[i] = uuid->uuid[15 - i];
18840ce72b1SMarcel Holtmann
18940ce72b1SMarcel Holtmann seq_printf(f, "%pUb\n", val);
19040ce72b1SMarcel Holtmann }
19140ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
19240ce72b1SMarcel Holtmann
19340ce72b1SMarcel Holtmann return 0;
19440ce72b1SMarcel Holtmann }
19540ce72b1SMarcel Holtmann
19622b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(uuids);
19740ce72b1SMarcel Holtmann
remote_oob_show(struct seq_file * f,void * ptr)1986858bcd0SMarcel Holtmann static int remote_oob_show(struct seq_file *f, void *ptr)
1996858bcd0SMarcel Holtmann {
2006858bcd0SMarcel Holtmann struct hci_dev *hdev = f->private;
2016858bcd0SMarcel Holtmann struct oob_data *data;
2026858bcd0SMarcel Holtmann
2036858bcd0SMarcel Holtmann hci_dev_lock(hdev);
2046858bcd0SMarcel Holtmann list_for_each_entry(data, &hdev->remote_oob_data, list) {
2056858bcd0SMarcel Holtmann seq_printf(f, "%pMR (type %u) %u %*phN %*phN %*phN %*phN\n",
2066858bcd0SMarcel Holtmann &data->bdaddr, data->bdaddr_type, data->present,
2076858bcd0SMarcel Holtmann 16, data->hash192, 16, data->rand192,
208b880ab86SMarcel Holtmann 16, data->hash256, 16, data->rand256);
2096858bcd0SMarcel Holtmann }
2106858bcd0SMarcel Holtmann hci_dev_unlock(hdev);
2116858bcd0SMarcel Holtmann
2126858bcd0SMarcel Holtmann return 0;
2136858bcd0SMarcel Holtmann }
2146858bcd0SMarcel Holtmann
21522b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(remote_oob);
2166858bcd0SMarcel Holtmann
conn_info_min_age_set(void * data,u64 val)21740ce72b1SMarcel Holtmann static int conn_info_min_age_set(void *data, u64 val)
21840ce72b1SMarcel Holtmann {
21940ce72b1SMarcel Holtmann struct hci_dev *hdev = data;
22040ce72b1SMarcel Holtmann
22140ce72b1SMarcel Holtmann hci_dev_lock(hdev);
222*d75632d0SBastien Nocera if (val == 0 || val > hdev->conn_info_max_age) {
223*d75632d0SBastien Nocera hci_dev_unlock(hdev);
224*d75632d0SBastien Nocera return -EINVAL;
225*d75632d0SBastien Nocera }
226*d75632d0SBastien Nocera
22740ce72b1SMarcel Holtmann hdev->conn_info_min_age = val;
22840ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
22940ce72b1SMarcel Holtmann
23040ce72b1SMarcel Holtmann return 0;
23140ce72b1SMarcel Holtmann }
23240ce72b1SMarcel Holtmann
conn_info_min_age_get(void * data,u64 * val)23340ce72b1SMarcel Holtmann static int conn_info_min_age_get(void *data, u64 *val)
23440ce72b1SMarcel Holtmann {
23540ce72b1SMarcel Holtmann struct hci_dev *hdev = data;
23640ce72b1SMarcel Holtmann
23740ce72b1SMarcel Holtmann hci_dev_lock(hdev);
23840ce72b1SMarcel Holtmann *val = hdev->conn_info_min_age;
23940ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
24040ce72b1SMarcel Holtmann
24140ce72b1SMarcel Holtmann return 0;
24240ce72b1SMarcel Holtmann }
24340ce72b1SMarcel Holtmann
244231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get,
24540ce72b1SMarcel Holtmann conn_info_min_age_set, "%llu\n");
24640ce72b1SMarcel Holtmann
conn_info_max_age_set(void * data,u64 val)24740ce72b1SMarcel Holtmann static int conn_info_max_age_set(void *data, u64 val)
24840ce72b1SMarcel Holtmann {
24940ce72b1SMarcel Holtmann struct hci_dev *hdev = data;
25040ce72b1SMarcel Holtmann
25140ce72b1SMarcel Holtmann hci_dev_lock(hdev);
252*d75632d0SBastien Nocera if (val == 0 || val < hdev->conn_info_min_age) {
253*d75632d0SBastien Nocera hci_dev_unlock(hdev);
254*d75632d0SBastien Nocera return -EINVAL;
255*d75632d0SBastien Nocera }
256*d75632d0SBastien Nocera
25740ce72b1SMarcel Holtmann hdev->conn_info_max_age = val;
25840ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
25940ce72b1SMarcel Holtmann
26040ce72b1SMarcel Holtmann return 0;
26140ce72b1SMarcel Holtmann }
26240ce72b1SMarcel Holtmann
conn_info_max_age_get(void * data,u64 * val)26340ce72b1SMarcel Holtmann static int conn_info_max_age_get(void *data, u64 *val)
26440ce72b1SMarcel Holtmann {
26540ce72b1SMarcel Holtmann struct hci_dev *hdev = data;
26640ce72b1SMarcel Holtmann
26740ce72b1SMarcel Holtmann hci_dev_lock(hdev);
26840ce72b1SMarcel Holtmann *val = hdev->conn_info_max_age;
26940ce72b1SMarcel Holtmann hci_dev_unlock(hdev);
27040ce72b1SMarcel Holtmann
27140ce72b1SMarcel Holtmann return 0;
27240ce72b1SMarcel Holtmann }
27340ce72b1SMarcel Holtmann
274231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(conn_info_max_age_fops, conn_info_max_age_get,
27540ce72b1SMarcel Holtmann conn_info_max_age_set, "%llu\n");
27640ce72b1SMarcel Holtmann
use_debug_keys_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2770886aea6SMarcel Holtmann static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf,
2780886aea6SMarcel Holtmann size_t count, loff_t *ppos)
2790886aea6SMarcel Holtmann {
2800886aea6SMarcel Holtmann struct hci_dev *hdev = file->private_data;
2810886aea6SMarcel Holtmann char buf[3];
2820886aea6SMarcel Holtmann
283d7a5a11dSMarcel Holtmann buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y' : 'N';
2840886aea6SMarcel Holtmann buf[1] = '\n';
2850886aea6SMarcel Holtmann buf[2] = '\0';
2860886aea6SMarcel Holtmann return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
2870886aea6SMarcel Holtmann }
2880886aea6SMarcel Holtmann
2890886aea6SMarcel Holtmann static const struct file_operations use_debug_keys_fops = {
2900886aea6SMarcel Holtmann .open = simple_open,
2910886aea6SMarcel Holtmann .read = use_debug_keys_read,
2920886aea6SMarcel Holtmann .llseek = default_llseek,
2930886aea6SMarcel Holtmann };
2940886aea6SMarcel Holtmann
sc_only_mode_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)295cb0d2faeSMarcel Holtmann static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
296cb0d2faeSMarcel Holtmann size_t count, loff_t *ppos)
297cb0d2faeSMarcel Holtmann {
298cb0d2faeSMarcel Holtmann struct hci_dev *hdev = file->private_data;
299cb0d2faeSMarcel Holtmann char buf[3];
300cb0d2faeSMarcel Holtmann
301d7a5a11dSMarcel Holtmann buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y' : 'N';
302cb0d2faeSMarcel Holtmann buf[1] = '\n';
303cb0d2faeSMarcel Holtmann buf[2] = '\0';
304cb0d2faeSMarcel Holtmann return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
305cb0d2faeSMarcel Holtmann }
306cb0d2faeSMarcel Holtmann
307cb0d2faeSMarcel Holtmann static const struct file_operations sc_only_mode_fops = {
308cb0d2faeSMarcel Holtmann .open = simple_open,
309cb0d2faeSMarcel Holtmann .read = sc_only_mode_read,
310cb0d2faeSMarcel Holtmann .llseek = default_llseek,
311cb0d2faeSMarcel Holtmann };
312cb0d2faeSMarcel Holtmann
3135177a838SMarcel Holtmann DEFINE_INFO_ATTRIBUTE(hardware_info, hw_info);
3145177a838SMarcel Holtmann DEFINE_INFO_ATTRIBUTE(firmware_info, fw_info);
3155177a838SMarcel Holtmann
hci_debugfs_create_common(struct hci_dev * hdev)31660c5f5fbSMarcel Holtmann void hci_debugfs_create_common(struct hci_dev *hdev)
31760c5f5fbSMarcel Holtmann {
31840ce72b1SMarcel Holtmann debugfs_create_file("features", 0444, hdev->debugfs, hdev,
31940ce72b1SMarcel Holtmann &features_fops);
32040ce72b1SMarcel Holtmann debugfs_create_u16("manufacturer", 0444, hdev->debugfs,
32140ce72b1SMarcel Holtmann &hdev->manufacturer);
32240ce72b1SMarcel Holtmann debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver);
32340ce72b1SMarcel Holtmann debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev);
3245789f37cSMarcel Holtmann debugfs_create_u8("hardware_error", 0444, hdev->debugfs,
3255789f37cSMarcel Holtmann &hdev->hw_error_code);
326c3370de6SMarcel Holtmann debugfs_create_file("device_id", 0444, hdev->debugfs, hdev,
327c3370de6SMarcel Holtmann &device_id_fops);
3285789f37cSMarcel Holtmann
32940ce72b1SMarcel Holtmann debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
33040ce72b1SMarcel Holtmann &device_list_fops);
33140ce72b1SMarcel Holtmann debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev,
33240ce72b1SMarcel Holtmann &blacklist_fops);
333600a8749SAlain Michaud debugfs_create_file("blocked_keys", 0444, hdev->debugfs, hdev,
334600a8749SAlain Michaud &blocked_keys_fops);
33540ce72b1SMarcel Holtmann debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
3366858bcd0SMarcel Holtmann debugfs_create_file("remote_oob", 0400, hdev->debugfs, hdev,
3376858bcd0SMarcel Holtmann &remote_oob_fops);
33840ce72b1SMarcel Holtmann
33940ce72b1SMarcel Holtmann debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev,
34040ce72b1SMarcel Holtmann &conn_info_min_age_fops);
34140ce72b1SMarcel Holtmann debugfs_create_file("conn_info_max_age", 0644, hdev->debugfs, hdev,
34240ce72b1SMarcel Holtmann &conn_info_max_age_fops);
343cb0d2faeSMarcel Holtmann
3440886aea6SMarcel Holtmann if (lmp_ssp_capable(hdev) || lmp_le_capable(hdev))
3450886aea6SMarcel Holtmann debugfs_create_file("use_debug_keys", 0444, hdev->debugfs,
3460886aea6SMarcel Holtmann hdev, &use_debug_keys_fops);
3470886aea6SMarcel Holtmann
348cb0d2faeSMarcel Holtmann if (lmp_sc_capable(hdev) || lmp_le_capable(hdev))
349cb0d2faeSMarcel Holtmann debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
350cb0d2faeSMarcel Holtmann hdev, &sc_only_mode_fops);
3515177a838SMarcel Holtmann
3525177a838SMarcel Holtmann if (hdev->hw_info)
3535177a838SMarcel Holtmann debugfs_create_file("hardware_info", 0444, hdev->debugfs,
3545177a838SMarcel Holtmann hdev, &hardware_info_fops);
3555177a838SMarcel Holtmann
3565177a838SMarcel Holtmann if (hdev->fw_info)
3575177a838SMarcel Holtmann debugfs_create_file("firmware_info", 0444, hdev->debugfs,
3585177a838SMarcel Holtmann hdev, &firmware_info_fops);
35960c5f5fbSMarcel Holtmann }
36060c5f5fbSMarcel Holtmann
inquiry_cache_show(struct seq_file * f,void * p)36171c3b60eSMarcel Holtmann static int inquiry_cache_show(struct seq_file *f, void *p)
36271c3b60eSMarcel Holtmann {
36371c3b60eSMarcel Holtmann struct hci_dev *hdev = f->private;
36471c3b60eSMarcel Holtmann struct discovery_state *cache = &hdev->discovery;
36571c3b60eSMarcel Holtmann struct inquiry_entry *e;
36671c3b60eSMarcel Holtmann
36771c3b60eSMarcel Holtmann hci_dev_lock(hdev);
36871c3b60eSMarcel Holtmann
36971c3b60eSMarcel Holtmann list_for_each_entry(e, &cache->all, all) {
37071c3b60eSMarcel Holtmann struct inquiry_data *data = &e->data;
37171c3b60eSMarcel Holtmann seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
37271c3b60eSMarcel Holtmann &data->bdaddr,
37371c3b60eSMarcel Holtmann data->pscan_rep_mode, data->pscan_period_mode,
37471c3b60eSMarcel Holtmann data->pscan_mode, data->dev_class[2],
37571c3b60eSMarcel Holtmann data->dev_class[1], data->dev_class[0],
37671c3b60eSMarcel Holtmann __le16_to_cpu(data->clock_offset),
37771c3b60eSMarcel Holtmann data->rssi, data->ssp_mode, e->timestamp);
37871c3b60eSMarcel Holtmann }
37971c3b60eSMarcel Holtmann
38071c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
38171c3b60eSMarcel Holtmann
38271c3b60eSMarcel Holtmann return 0;
38371c3b60eSMarcel Holtmann }
38471c3b60eSMarcel Holtmann
38522b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(inquiry_cache);
38671c3b60eSMarcel Holtmann
link_keys_show(struct seq_file * f,void * ptr)38771c3b60eSMarcel Holtmann static int link_keys_show(struct seq_file *f, void *ptr)
38871c3b60eSMarcel Holtmann {
38971c3b60eSMarcel Holtmann struct hci_dev *hdev = f->private;
39071c3b60eSMarcel Holtmann struct link_key *key;
39171c3b60eSMarcel Holtmann
39271c3b60eSMarcel Holtmann rcu_read_lock();
39371c3b60eSMarcel Holtmann list_for_each_entry_rcu(key, &hdev->link_keys, list)
39471c3b60eSMarcel Holtmann seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type,
39571c3b60eSMarcel Holtmann HCI_LINK_KEY_SIZE, key->val, key->pin_len);
39671c3b60eSMarcel Holtmann rcu_read_unlock();
39771c3b60eSMarcel Holtmann
39871c3b60eSMarcel Holtmann return 0;
39971c3b60eSMarcel Holtmann }
40071c3b60eSMarcel Holtmann
40122b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(link_keys);
40271c3b60eSMarcel Holtmann
dev_class_show(struct seq_file * f,void * ptr)40371c3b60eSMarcel Holtmann static int dev_class_show(struct seq_file *f, void *ptr)
40471c3b60eSMarcel Holtmann {
40571c3b60eSMarcel Holtmann struct hci_dev *hdev = f->private;
40671c3b60eSMarcel Holtmann
40771c3b60eSMarcel Holtmann hci_dev_lock(hdev);
40871c3b60eSMarcel Holtmann seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
40971c3b60eSMarcel Holtmann hdev->dev_class[1], hdev->dev_class[0]);
41071c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
41171c3b60eSMarcel Holtmann
41271c3b60eSMarcel Holtmann return 0;
41371c3b60eSMarcel Holtmann }
41471c3b60eSMarcel Holtmann
41522b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(dev_class);
41671c3b60eSMarcel Holtmann
voice_setting_get(void * data,u64 * val)41771c3b60eSMarcel Holtmann static int voice_setting_get(void *data, u64 *val)
41871c3b60eSMarcel Holtmann {
41971c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
42071c3b60eSMarcel Holtmann
42171c3b60eSMarcel Holtmann hci_dev_lock(hdev);
42271c3b60eSMarcel Holtmann *val = hdev->voice_setting;
42371c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
42471c3b60eSMarcel Holtmann
42571c3b60eSMarcel Holtmann return 0;
42671c3b60eSMarcel Holtmann }
42771c3b60eSMarcel Holtmann
428231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(voice_setting_fops, voice_setting_get,
42971c3b60eSMarcel Holtmann NULL, "0x%4.4llx\n");
43071c3b60eSMarcel Holtmann
ssp_debug_mode_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)4316e07231aSMarcel Holtmann static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf,
4326e07231aSMarcel Holtmann size_t count, loff_t *ppos)
4336e07231aSMarcel Holtmann {
4346e07231aSMarcel Holtmann struct hci_dev *hdev = file->private_data;
4356e07231aSMarcel Holtmann char buf[3];
4366e07231aSMarcel Holtmann
4376e07231aSMarcel Holtmann buf[0] = hdev->ssp_debug_mode ? 'Y' : 'N';
4386e07231aSMarcel Holtmann buf[1] = '\n';
4396e07231aSMarcel Holtmann buf[2] = '\0';
4406e07231aSMarcel Holtmann return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
4416e07231aSMarcel Holtmann }
4426e07231aSMarcel Holtmann
4436e07231aSMarcel Holtmann static const struct file_operations ssp_debug_mode_fops = {
4446e07231aSMarcel Holtmann .open = simple_open,
4456e07231aSMarcel Holtmann .read = ssp_debug_mode_read,
4466e07231aSMarcel Holtmann .llseek = default_llseek,
4476e07231aSMarcel Holtmann };
4486e07231aSMarcel Holtmann
auto_accept_delay_set(void * data,u64 val)44971c3b60eSMarcel Holtmann static int auto_accept_delay_set(void *data, u64 val)
45071c3b60eSMarcel Holtmann {
45171c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
45271c3b60eSMarcel Holtmann
45371c3b60eSMarcel Holtmann hci_dev_lock(hdev);
45471c3b60eSMarcel Holtmann hdev->auto_accept_delay = val;
45571c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
45671c3b60eSMarcel Holtmann
45771c3b60eSMarcel Holtmann return 0;
45871c3b60eSMarcel Holtmann }
45971c3b60eSMarcel Holtmann
min_encrypt_key_size_set(void * data,u64 val)46058a96fc3SMarcel Holtmann static int min_encrypt_key_size_set(void *data, u64 val)
46158a96fc3SMarcel Holtmann {
46258a96fc3SMarcel Holtmann struct hci_dev *hdev = data;
46358a96fc3SMarcel Holtmann
46458a96fc3SMarcel Holtmann if (val < 1 || val > 16)
46558a96fc3SMarcel Holtmann return -EINVAL;
46658a96fc3SMarcel Holtmann
46758a96fc3SMarcel Holtmann hci_dev_lock(hdev);
46858a96fc3SMarcel Holtmann hdev->min_enc_key_size = val;
46958a96fc3SMarcel Holtmann hci_dev_unlock(hdev);
47058a96fc3SMarcel Holtmann
47158a96fc3SMarcel Holtmann return 0;
47258a96fc3SMarcel Holtmann }
47358a96fc3SMarcel Holtmann
min_encrypt_key_size_get(void * data,u64 * val)47458a96fc3SMarcel Holtmann static int min_encrypt_key_size_get(void *data, u64 *val)
47558a96fc3SMarcel Holtmann {
47658a96fc3SMarcel Holtmann struct hci_dev *hdev = data;
47758a96fc3SMarcel Holtmann
47858a96fc3SMarcel Holtmann hci_dev_lock(hdev);
47958a96fc3SMarcel Holtmann *val = hdev->min_enc_key_size;
48058a96fc3SMarcel Holtmann hci_dev_unlock(hdev);
48158a96fc3SMarcel Holtmann
48258a96fc3SMarcel Holtmann return 0;
48358a96fc3SMarcel Holtmann }
48458a96fc3SMarcel Holtmann
485231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(min_encrypt_key_size_fops,
48658a96fc3SMarcel Holtmann min_encrypt_key_size_get,
48758a96fc3SMarcel Holtmann min_encrypt_key_size_set, "%llu\n");
48858a96fc3SMarcel Holtmann
auto_accept_delay_get(void * data,u64 * val)48971c3b60eSMarcel Holtmann static int auto_accept_delay_get(void *data, u64 *val)
49071c3b60eSMarcel Holtmann {
49171c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
49271c3b60eSMarcel Holtmann
49371c3b60eSMarcel Holtmann hci_dev_lock(hdev);
49471c3b60eSMarcel Holtmann *val = hdev->auto_accept_delay;
49571c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
49671c3b60eSMarcel Holtmann
49771c3b60eSMarcel Holtmann return 0;
49871c3b60eSMarcel Holtmann }
49971c3b60eSMarcel Holtmann
500231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
50171c3b60eSMarcel Holtmann auto_accept_delay_set, "%llu\n");
50271c3b60eSMarcel Holtmann
force_bredr_smp_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)50382493316SClaire Chang static ssize_t force_bredr_smp_read(struct file *file,
50482493316SClaire Chang char __user *user_buf,
50582493316SClaire Chang size_t count, loff_t *ppos)
50682493316SClaire Chang {
50782493316SClaire Chang struct hci_dev *hdev = file->private_data;
50882493316SClaire Chang char buf[3];
50982493316SClaire Chang
51082493316SClaire Chang buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP) ? 'Y' : 'N';
51182493316SClaire Chang buf[1] = '\n';
51282493316SClaire Chang buf[2] = '\0';
51382493316SClaire Chang return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
51482493316SClaire Chang }
51582493316SClaire Chang
force_bredr_smp_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)51682493316SClaire Chang static ssize_t force_bredr_smp_write(struct file *file,
51782493316SClaire Chang const char __user *user_buf,
51882493316SClaire Chang size_t count, loff_t *ppos)
51982493316SClaire Chang {
52082493316SClaire Chang struct hci_dev *hdev = file->private_data;
52182493316SClaire Chang bool enable;
52282493316SClaire Chang int err;
52382493316SClaire Chang
52482493316SClaire Chang err = kstrtobool_from_user(user_buf, count, &enable);
52582493316SClaire Chang if (err)
52682493316SClaire Chang return err;
52782493316SClaire Chang
52882493316SClaire Chang err = smp_force_bredr(hdev, enable);
52982493316SClaire Chang if (err)
53082493316SClaire Chang return err;
53182493316SClaire Chang
53282493316SClaire Chang return count;
53382493316SClaire Chang }
53482493316SClaire Chang
53582493316SClaire Chang static const struct file_operations force_bredr_smp_fops = {
53682493316SClaire Chang .open = simple_open,
53782493316SClaire Chang .read = force_bredr_smp_read,
53882493316SClaire Chang .write = force_bredr_smp_write,
53982493316SClaire Chang .llseek = default_llseek,
54082493316SClaire Chang };
54182493316SClaire Chang
idle_timeout_set(void * data,u64 val)54271c3b60eSMarcel Holtmann static int idle_timeout_set(void *data, u64 val)
54371c3b60eSMarcel Holtmann {
54471c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
54571c3b60eSMarcel Holtmann
54671c3b60eSMarcel Holtmann if (val != 0 && (val < 500 || val > 3600000))
54771c3b60eSMarcel Holtmann return -EINVAL;
54871c3b60eSMarcel Holtmann
54971c3b60eSMarcel Holtmann hci_dev_lock(hdev);
55071c3b60eSMarcel Holtmann hdev->idle_timeout = val;
55171c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
55271c3b60eSMarcel Holtmann
55371c3b60eSMarcel Holtmann return 0;
55471c3b60eSMarcel Holtmann }
55571c3b60eSMarcel Holtmann
idle_timeout_get(void * data,u64 * val)55671c3b60eSMarcel Holtmann static int idle_timeout_get(void *data, u64 *val)
55771c3b60eSMarcel Holtmann {
55871c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
55971c3b60eSMarcel Holtmann
56071c3b60eSMarcel Holtmann hci_dev_lock(hdev);
56171c3b60eSMarcel Holtmann *val = hdev->idle_timeout;
56271c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
56371c3b60eSMarcel Holtmann
56471c3b60eSMarcel Holtmann return 0;
56571c3b60eSMarcel Holtmann }
56671c3b60eSMarcel Holtmann
567231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(idle_timeout_fops, idle_timeout_get,
56871c3b60eSMarcel Holtmann idle_timeout_set, "%llu\n");
56971c3b60eSMarcel Holtmann
sniff_min_interval_set(void * data,u64 val)57071c3b60eSMarcel Holtmann static int sniff_min_interval_set(void *data, u64 val)
57171c3b60eSMarcel Holtmann {
57271c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
57371c3b60eSMarcel Holtmann
57471c3b60eSMarcel Holtmann hci_dev_lock(hdev);
575*d75632d0SBastien Nocera if (val == 0 || val % 2 || val > hdev->sniff_max_interval) {
576*d75632d0SBastien Nocera hci_dev_unlock(hdev);
577*d75632d0SBastien Nocera return -EINVAL;
578*d75632d0SBastien Nocera }
579*d75632d0SBastien Nocera
58071c3b60eSMarcel Holtmann hdev->sniff_min_interval = val;
58171c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
58271c3b60eSMarcel Holtmann
58371c3b60eSMarcel Holtmann return 0;
58471c3b60eSMarcel Holtmann }
58571c3b60eSMarcel Holtmann
sniff_min_interval_get(void * data,u64 * val)58671c3b60eSMarcel Holtmann static int sniff_min_interval_get(void *data, u64 *val)
58771c3b60eSMarcel Holtmann {
58871c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
58971c3b60eSMarcel Holtmann
59071c3b60eSMarcel Holtmann hci_dev_lock(hdev);
59171c3b60eSMarcel Holtmann *val = hdev->sniff_min_interval;
59271c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
59371c3b60eSMarcel Holtmann
59471c3b60eSMarcel Holtmann return 0;
59571c3b60eSMarcel Holtmann }
59671c3b60eSMarcel Holtmann
597231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(sniff_min_interval_fops, sniff_min_interval_get,
59871c3b60eSMarcel Holtmann sniff_min_interval_set, "%llu\n");
59971c3b60eSMarcel Holtmann
sniff_max_interval_set(void * data,u64 val)60071c3b60eSMarcel Holtmann static int sniff_max_interval_set(void *data, u64 val)
60171c3b60eSMarcel Holtmann {
60271c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
60371c3b60eSMarcel Holtmann
60471c3b60eSMarcel Holtmann hci_dev_lock(hdev);
605*d75632d0SBastien Nocera if (val == 0 || val % 2 || val < hdev->sniff_min_interval) {
606*d75632d0SBastien Nocera hci_dev_unlock(hdev);
607*d75632d0SBastien Nocera return -EINVAL;
608*d75632d0SBastien Nocera }
609*d75632d0SBastien Nocera
61071c3b60eSMarcel Holtmann hdev->sniff_max_interval = val;
61171c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
61271c3b60eSMarcel Holtmann
61371c3b60eSMarcel Holtmann return 0;
61471c3b60eSMarcel Holtmann }
61571c3b60eSMarcel Holtmann
sniff_max_interval_get(void * data,u64 * val)61671c3b60eSMarcel Holtmann static int sniff_max_interval_get(void *data, u64 *val)
61771c3b60eSMarcel Holtmann {
61871c3b60eSMarcel Holtmann struct hci_dev *hdev = data;
61971c3b60eSMarcel Holtmann
62071c3b60eSMarcel Holtmann hci_dev_lock(hdev);
62171c3b60eSMarcel Holtmann *val = hdev->sniff_max_interval;
62271c3b60eSMarcel Holtmann hci_dev_unlock(hdev);
62371c3b60eSMarcel Holtmann
62471c3b60eSMarcel Holtmann return 0;
62571c3b60eSMarcel Holtmann }
62671c3b60eSMarcel Holtmann
627231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get,
62871c3b60eSMarcel Holtmann sniff_max_interval_set, "%llu\n");
62971c3b60eSMarcel Holtmann
hci_debugfs_create_bredr(struct hci_dev * hdev)63060c5f5fbSMarcel Holtmann void hci_debugfs_create_bredr(struct hci_dev *hdev)
63160c5f5fbSMarcel Holtmann {
63271c3b60eSMarcel Holtmann debugfs_create_file("inquiry_cache", 0444, hdev->debugfs, hdev,
63371c3b60eSMarcel Holtmann &inquiry_cache_fops);
63471c3b60eSMarcel Holtmann debugfs_create_file("link_keys", 0400, hdev->debugfs, hdev,
63571c3b60eSMarcel Holtmann &link_keys_fops);
63671c3b60eSMarcel Holtmann debugfs_create_file("dev_class", 0444, hdev->debugfs, hdev,
63771c3b60eSMarcel Holtmann &dev_class_fops);
63871c3b60eSMarcel Holtmann debugfs_create_file("voice_setting", 0444, hdev->debugfs, hdev,
63971c3b60eSMarcel Holtmann &voice_setting_fops);
64071c3b60eSMarcel Holtmann
64182493316SClaire Chang /* If the controller does not support BR/EDR Secure Connections
64282493316SClaire Chang * feature, then the BR/EDR SMP channel shall not be present.
64382493316SClaire Chang *
64482493316SClaire Chang * To test this with Bluetooth 4.0 controllers, create a debugfs
64582493316SClaire Chang * switch that allows forcing BR/EDR SMP support and accepting
64682493316SClaire Chang * cross-transport pairing on non-AES encrypted connections.
64782493316SClaire Chang */
64882493316SClaire Chang if (!lmp_sc_capable(hdev))
64982493316SClaire Chang debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs,
65082493316SClaire Chang hdev, &force_bredr_smp_fops);
65182493316SClaire Chang
6526e07231aSMarcel Holtmann if (lmp_ssp_capable(hdev)) {
6536e07231aSMarcel Holtmann debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs,
6546e07231aSMarcel Holtmann hdev, &ssp_debug_mode_fops);
65558a96fc3SMarcel Holtmann debugfs_create_file("min_encrypt_key_size", 0644, hdev->debugfs,
65658a96fc3SMarcel Holtmann hdev, &min_encrypt_key_size_fops);
65771c3b60eSMarcel Holtmann debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs,
65871c3b60eSMarcel Holtmann hdev, &auto_accept_delay_fops);
6596e07231aSMarcel Holtmann }
66071c3b60eSMarcel Holtmann
66171c3b60eSMarcel Holtmann if (lmp_sniff_capable(hdev)) {
66271c3b60eSMarcel Holtmann debugfs_create_file("idle_timeout", 0644, hdev->debugfs,
66371c3b60eSMarcel Holtmann hdev, &idle_timeout_fops);
66471c3b60eSMarcel Holtmann debugfs_create_file("sniff_min_interval", 0644, hdev->debugfs,
66571c3b60eSMarcel Holtmann hdev, &sniff_min_interval_fops);
66671c3b60eSMarcel Holtmann debugfs_create_file("sniff_max_interval", 0644, hdev->debugfs,
66771c3b60eSMarcel Holtmann hdev, &sniff_max_interval_fops);
66871c3b60eSMarcel Holtmann }
66960c5f5fbSMarcel Holtmann }
67060c5f5fbSMarcel Holtmann
identity_show(struct seq_file * f,void * p)6713a5c82b7SMarcel Holtmann static int identity_show(struct seq_file *f, void *p)
6723a5c82b7SMarcel Holtmann {
6733a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
6743a5c82b7SMarcel Holtmann bdaddr_t addr;
6753a5c82b7SMarcel Holtmann u8 addr_type;
6763a5c82b7SMarcel Holtmann
6773a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
6783a5c82b7SMarcel Holtmann
6793a5c82b7SMarcel Holtmann hci_copy_identity_address(hdev, &addr, &addr_type);
6803a5c82b7SMarcel Holtmann
6813a5c82b7SMarcel Holtmann seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type,
6823a5c82b7SMarcel Holtmann 16, hdev->irk, &hdev->rpa);
6833a5c82b7SMarcel Holtmann
6843a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
6853a5c82b7SMarcel Holtmann
6863a5c82b7SMarcel Holtmann return 0;
6873a5c82b7SMarcel Holtmann }
6883a5c82b7SMarcel Holtmann
68922b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(identity);
6903a5c82b7SMarcel Holtmann
rpa_timeout_set(void * data,u64 val)6913a5c82b7SMarcel Holtmann static int rpa_timeout_set(void *data, u64 val)
6923a5c82b7SMarcel Holtmann {
6933a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
6943a5c82b7SMarcel Holtmann
6953a5c82b7SMarcel Holtmann /* Require the RPA timeout to be at least 30 seconds and at most
6963a5c82b7SMarcel Holtmann * 24 hours.
6973a5c82b7SMarcel Holtmann */
6983a5c82b7SMarcel Holtmann if (val < 30 || val > (60 * 60 * 24))
6993a5c82b7SMarcel Holtmann return -EINVAL;
7003a5c82b7SMarcel Holtmann
7013a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
7023a5c82b7SMarcel Holtmann hdev->rpa_timeout = val;
7033a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
7043a5c82b7SMarcel Holtmann
7053a5c82b7SMarcel Holtmann return 0;
7063a5c82b7SMarcel Holtmann }
7073a5c82b7SMarcel Holtmann
rpa_timeout_get(void * data,u64 * val)7083a5c82b7SMarcel Holtmann static int rpa_timeout_get(void *data, u64 *val)
7093a5c82b7SMarcel Holtmann {
7103a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
7113a5c82b7SMarcel Holtmann
7123a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
7133a5c82b7SMarcel Holtmann *val = hdev->rpa_timeout;
7143a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
7153a5c82b7SMarcel Holtmann
7163a5c82b7SMarcel Holtmann return 0;
7173a5c82b7SMarcel Holtmann }
7183a5c82b7SMarcel Holtmann
719231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get,
7203a5c82b7SMarcel Holtmann rpa_timeout_set, "%llu\n");
7213a5c82b7SMarcel Holtmann
random_address_show(struct seq_file * f,void * p)7223a5c82b7SMarcel Holtmann static int random_address_show(struct seq_file *f, void *p)
7233a5c82b7SMarcel Holtmann {
7243a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
7253a5c82b7SMarcel Holtmann
7263a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
7273a5c82b7SMarcel Holtmann seq_printf(f, "%pMR\n", &hdev->random_addr);
7283a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
7293a5c82b7SMarcel Holtmann
7303a5c82b7SMarcel Holtmann return 0;
7313a5c82b7SMarcel Holtmann }
7323a5c82b7SMarcel Holtmann
73322b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(random_address);
7343a5c82b7SMarcel Holtmann
static_address_show(struct seq_file * f,void * p)7353a5c82b7SMarcel Holtmann static int static_address_show(struct seq_file *f, void *p)
7363a5c82b7SMarcel Holtmann {
7373a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
7383a5c82b7SMarcel Holtmann
7393a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
7403a5c82b7SMarcel Holtmann seq_printf(f, "%pMR\n", &hdev->static_addr);
7413a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
7423a5c82b7SMarcel Holtmann
7433a5c82b7SMarcel Holtmann return 0;
7443a5c82b7SMarcel Holtmann }
7453a5c82b7SMarcel Holtmann
74622b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(static_address);
7473a5c82b7SMarcel Holtmann
force_static_address_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)7483a5c82b7SMarcel Holtmann static ssize_t force_static_address_read(struct file *file,
7493a5c82b7SMarcel Holtmann char __user *user_buf,
7503a5c82b7SMarcel Holtmann size_t count, loff_t *ppos)
7513a5c82b7SMarcel Holtmann {
7523a5c82b7SMarcel Holtmann struct hci_dev *hdev = file->private_data;
7533a5c82b7SMarcel Holtmann char buf[3];
7543a5c82b7SMarcel Holtmann
755b7cb93e5SMarcel Holtmann buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ? 'Y' : 'N';
7563a5c82b7SMarcel Holtmann buf[1] = '\n';
7573a5c82b7SMarcel Holtmann buf[2] = '\0';
7583a5c82b7SMarcel Holtmann return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
7593a5c82b7SMarcel Holtmann }
7603a5c82b7SMarcel Holtmann
force_static_address_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)7613a5c82b7SMarcel Holtmann static ssize_t force_static_address_write(struct file *file,
7623a5c82b7SMarcel Holtmann const char __user *user_buf,
7633a5c82b7SMarcel Holtmann size_t count, loff_t *ppos)
7643a5c82b7SMarcel Holtmann {
7653a5c82b7SMarcel Holtmann struct hci_dev *hdev = file->private_data;
7663a5c82b7SMarcel Holtmann bool enable;
7673bf5e97dSAndy Shevchenko int err;
7683a5c82b7SMarcel Holtmann
769eeb1aafeSLuiz Augusto von Dentz if (hdev_is_powered(hdev))
7703a5c82b7SMarcel Holtmann return -EBUSY;
7713a5c82b7SMarcel Holtmann
7723bf5e97dSAndy Shevchenko err = kstrtobool_from_user(user_buf, count, &enable);
7733bf5e97dSAndy Shevchenko if (err)
7743bf5e97dSAndy Shevchenko return err;
7753a5c82b7SMarcel Holtmann
776b7cb93e5SMarcel Holtmann if (enable == hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR))
7773a5c82b7SMarcel Holtmann return -EALREADY;
7783a5c82b7SMarcel Holtmann
779b7cb93e5SMarcel Holtmann hci_dev_change_flag(hdev, HCI_FORCE_STATIC_ADDR);
7803a5c82b7SMarcel Holtmann
7813a5c82b7SMarcel Holtmann return count;
7823a5c82b7SMarcel Holtmann }
7833a5c82b7SMarcel Holtmann
7843a5c82b7SMarcel Holtmann static const struct file_operations force_static_address_fops = {
7853a5c82b7SMarcel Holtmann .open = simple_open,
7863a5c82b7SMarcel Holtmann .read = force_static_address_read,
7873a5c82b7SMarcel Holtmann .write = force_static_address_write,
7883a5c82b7SMarcel Holtmann .llseek = default_llseek,
7893a5c82b7SMarcel Holtmann };
7903a5c82b7SMarcel Holtmann
white_list_show(struct seq_file * f,void * ptr)7913a5c82b7SMarcel Holtmann static int white_list_show(struct seq_file *f, void *ptr)
7923a5c82b7SMarcel Holtmann {
7933a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
7943a5c82b7SMarcel Holtmann struct bdaddr_list *b;
7953a5c82b7SMarcel Holtmann
7963a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
7973d4f9c00SArchie Pusaka list_for_each_entry(b, &hdev->le_accept_list, list)
7983a5c82b7SMarcel Holtmann seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
7993a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
8003a5c82b7SMarcel Holtmann
8013a5c82b7SMarcel Holtmann return 0;
8023a5c82b7SMarcel Holtmann }
8033a5c82b7SMarcel Holtmann
80422b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(white_list);
8053a5c82b7SMarcel Holtmann
resolv_list_show(struct seq_file * f,void * ptr)806cfdb0c2dSAnkit Navik static int resolv_list_show(struct seq_file *f, void *ptr)
807cfdb0c2dSAnkit Navik {
808cfdb0c2dSAnkit Navik struct hci_dev *hdev = f->private;
809cfdb0c2dSAnkit Navik struct bdaddr_list *b;
810cfdb0c2dSAnkit Navik
811cfdb0c2dSAnkit Navik hci_dev_lock(hdev);
812cfdb0c2dSAnkit Navik list_for_each_entry(b, &hdev->le_resolv_list, list)
813cfdb0c2dSAnkit Navik seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
814cfdb0c2dSAnkit Navik hci_dev_unlock(hdev);
815cfdb0c2dSAnkit Navik
816cfdb0c2dSAnkit Navik return 0;
817cfdb0c2dSAnkit Navik }
818cfdb0c2dSAnkit Navik
819cfdb0c2dSAnkit Navik DEFINE_SHOW_ATTRIBUTE(resolv_list);
820cfdb0c2dSAnkit Navik
identity_resolving_keys_show(struct seq_file * f,void * ptr)8213a5c82b7SMarcel Holtmann static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
8223a5c82b7SMarcel Holtmann {
8233a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
8243a5c82b7SMarcel Holtmann struct smp_irk *irk;
8253a5c82b7SMarcel Holtmann
8263a5c82b7SMarcel Holtmann rcu_read_lock();
8273a5c82b7SMarcel Holtmann list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
8283a5c82b7SMarcel Holtmann seq_printf(f, "%pMR (type %u) %*phN %pMR\n",
8293a5c82b7SMarcel Holtmann &irk->bdaddr, irk->addr_type,
8303a5c82b7SMarcel Holtmann 16, irk->val, &irk->rpa);
8313a5c82b7SMarcel Holtmann }
8323a5c82b7SMarcel Holtmann rcu_read_unlock();
8333a5c82b7SMarcel Holtmann
8343a5c82b7SMarcel Holtmann return 0;
8353a5c82b7SMarcel Holtmann }
8363a5c82b7SMarcel Holtmann
83722b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(identity_resolving_keys);
8383a5c82b7SMarcel Holtmann
long_term_keys_show(struct seq_file * f,void * ptr)8393a5c82b7SMarcel Holtmann static int long_term_keys_show(struct seq_file *f, void *ptr)
8403a5c82b7SMarcel Holtmann {
8413a5c82b7SMarcel Holtmann struct hci_dev *hdev = f->private;
8423a5c82b7SMarcel Holtmann struct smp_ltk *ltk;
8433a5c82b7SMarcel Holtmann
8443a5c82b7SMarcel Holtmann rcu_read_lock();
8453a5c82b7SMarcel Holtmann list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list)
8463a5c82b7SMarcel Holtmann seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n",
8473a5c82b7SMarcel Holtmann <k->bdaddr, ltk->bdaddr_type, ltk->authenticated,
8483a5c82b7SMarcel Holtmann ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv),
8493a5c82b7SMarcel Holtmann __le64_to_cpu(ltk->rand), 16, ltk->val);
8503a5c82b7SMarcel Holtmann rcu_read_unlock();
8513a5c82b7SMarcel Holtmann
8523a5c82b7SMarcel Holtmann return 0;
8533a5c82b7SMarcel Holtmann }
8543a5c82b7SMarcel Holtmann
85522b371cbSAndy Shevchenko DEFINE_SHOW_ATTRIBUTE(long_term_keys);
8563a5c82b7SMarcel Holtmann
conn_min_interval_set(void * data,u64 val)8573a5c82b7SMarcel Holtmann static int conn_min_interval_set(void *data, u64 val)
8583a5c82b7SMarcel Holtmann {
8593a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
8603a5c82b7SMarcel Holtmann
8613a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
862*d75632d0SBastien Nocera if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) {
863*d75632d0SBastien Nocera hci_dev_unlock(hdev);
864*d75632d0SBastien Nocera return -EINVAL;
865*d75632d0SBastien Nocera }
866*d75632d0SBastien Nocera
8673a5c82b7SMarcel Holtmann hdev->le_conn_min_interval = val;
8683a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
8693a5c82b7SMarcel Holtmann
8703a5c82b7SMarcel Holtmann return 0;
8713a5c82b7SMarcel Holtmann }
8723a5c82b7SMarcel Holtmann
conn_min_interval_get(void * data,u64 * val)8733a5c82b7SMarcel Holtmann static int conn_min_interval_get(void *data, u64 *val)
8743a5c82b7SMarcel Holtmann {
8753a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
8763a5c82b7SMarcel Holtmann
8773a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
8783a5c82b7SMarcel Holtmann *val = hdev->le_conn_min_interval;
8793a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
8803a5c82b7SMarcel Holtmann
8813a5c82b7SMarcel Holtmann return 0;
8823a5c82b7SMarcel Holtmann }
8833a5c82b7SMarcel Holtmann
884231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(conn_min_interval_fops, conn_min_interval_get,
8853a5c82b7SMarcel Holtmann conn_min_interval_set, "%llu\n");
8863a5c82b7SMarcel Holtmann
conn_max_interval_set(void * data,u64 val)8873a5c82b7SMarcel Holtmann static int conn_max_interval_set(void *data, u64 val)
8883a5c82b7SMarcel Holtmann {
8893a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
8903a5c82b7SMarcel Holtmann
8913a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
892*d75632d0SBastien Nocera if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) {
893*d75632d0SBastien Nocera hci_dev_unlock(hdev);
894*d75632d0SBastien Nocera return -EINVAL;
895*d75632d0SBastien Nocera }
896*d75632d0SBastien Nocera
8973a5c82b7SMarcel Holtmann hdev->le_conn_max_interval = val;
8983a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
8993a5c82b7SMarcel Holtmann
9003a5c82b7SMarcel Holtmann return 0;
9013a5c82b7SMarcel Holtmann }
9023a5c82b7SMarcel Holtmann
conn_max_interval_get(void * data,u64 * val)9033a5c82b7SMarcel Holtmann static int conn_max_interval_get(void *data, u64 *val)
9043a5c82b7SMarcel Holtmann {
9053a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9063a5c82b7SMarcel Holtmann
9073a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9083a5c82b7SMarcel Holtmann *val = hdev->le_conn_max_interval;
9093a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9103a5c82b7SMarcel Holtmann
9113a5c82b7SMarcel Holtmann return 0;
9123a5c82b7SMarcel Holtmann }
9133a5c82b7SMarcel Holtmann
914231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get,
9153a5c82b7SMarcel Holtmann conn_max_interval_set, "%llu\n");
9163a5c82b7SMarcel Holtmann
conn_latency_set(void * data,u64 val)9173a5c82b7SMarcel Holtmann static int conn_latency_set(void *data, u64 val)
9183a5c82b7SMarcel Holtmann {
9193a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9203a5c82b7SMarcel Holtmann
9213a5c82b7SMarcel Holtmann if (val > 0x01f3)
9223a5c82b7SMarcel Holtmann return -EINVAL;
9233a5c82b7SMarcel Holtmann
9243a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9253a5c82b7SMarcel Holtmann hdev->le_conn_latency = val;
9263a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9273a5c82b7SMarcel Holtmann
9283a5c82b7SMarcel Holtmann return 0;
9293a5c82b7SMarcel Holtmann }
9303a5c82b7SMarcel Holtmann
conn_latency_get(void * data,u64 * val)9313a5c82b7SMarcel Holtmann static int conn_latency_get(void *data, u64 *val)
9323a5c82b7SMarcel Holtmann {
9333a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9343a5c82b7SMarcel Holtmann
9353a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9363a5c82b7SMarcel Holtmann *val = hdev->le_conn_latency;
9373a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9383a5c82b7SMarcel Holtmann
9393a5c82b7SMarcel Holtmann return 0;
9403a5c82b7SMarcel Holtmann }
9413a5c82b7SMarcel Holtmann
942231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(conn_latency_fops, conn_latency_get,
9433a5c82b7SMarcel Holtmann conn_latency_set, "%llu\n");
9443a5c82b7SMarcel Holtmann
supervision_timeout_set(void * data,u64 val)9453a5c82b7SMarcel Holtmann static int supervision_timeout_set(void *data, u64 val)
9463a5c82b7SMarcel Holtmann {
9473a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9483a5c82b7SMarcel Holtmann
9493a5c82b7SMarcel Holtmann if (val < 0x000a || val > 0x0c80)
9503a5c82b7SMarcel Holtmann return -EINVAL;
9513a5c82b7SMarcel Holtmann
9523a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9533a5c82b7SMarcel Holtmann hdev->le_supv_timeout = val;
9543a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9553a5c82b7SMarcel Holtmann
9563a5c82b7SMarcel Holtmann return 0;
9573a5c82b7SMarcel Holtmann }
9583a5c82b7SMarcel Holtmann
supervision_timeout_get(void * data,u64 * val)9593a5c82b7SMarcel Holtmann static int supervision_timeout_get(void *data, u64 *val)
9603a5c82b7SMarcel Holtmann {
9613a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9623a5c82b7SMarcel Holtmann
9633a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9643a5c82b7SMarcel Holtmann *val = hdev->le_supv_timeout;
9653a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9663a5c82b7SMarcel Holtmann
9673a5c82b7SMarcel Holtmann return 0;
9683a5c82b7SMarcel Holtmann }
9693a5c82b7SMarcel Holtmann
970231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get,
9713a5c82b7SMarcel Holtmann supervision_timeout_set, "%llu\n");
9723a5c82b7SMarcel Holtmann
adv_channel_map_set(void * data,u64 val)9733a5c82b7SMarcel Holtmann static int adv_channel_map_set(void *data, u64 val)
9743a5c82b7SMarcel Holtmann {
9753a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9763a5c82b7SMarcel Holtmann
9773a5c82b7SMarcel Holtmann if (val < 0x01 || val > 0x07)
9783a5c82b7SMarcel Holtmann return -EINVAL;
9793a5c82b7SMarcel Holtmann
9803a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9813a5c82b7SMarcel Holtmann hdev->le_adv_channel_map = val;
9823a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9833a5c82b7SMarcel Holtmann
9843a5c82b7SMarcel Holtmann return 0;
9853a5c82b7SMarcel Holtmann }
9863a5c82b7SMarcel Holtmann
adv_channel_map_get(void * data,u64 * val)9873a5c82b7SMarcel Holtmann static int adv_channel_map_get(void *data, u64 *val)
9883a5c82b7SMarcel Holtmann {
9893a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
9903a5c82b7SMarcel Holtmann
9913a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
9923a5c82b7SMarcel Holtmann *val = hdev->le_adv_channel_map;
9933a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
9943a5c82b7SMarcel Holtmann
9953a5c82b7SMarcel Holtmann return 0;
9963a5c82b7SMarcel Holtmann }
9973a5c82b7SMarcel Holtmann
998231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get,
9993a5c82b7SMarcel Holtmann adv_channel_map_set, "%llu\n");
10003a5c82b7SMarcel Holtmann
adv_min_interval_set(void * data,u64 val)10013a5c82b7SMarcel Holtmann static int adv_min_interval_set(void *data, u64 val)
10023a5c82b7SMarcel Holtmann {
10033a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
10043a5c82b7SMarcel Holtmann
10053a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
1006*d75632d0SBastien Nocera if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) {
1007*d75632d0SBastien Nocera hci_dev_unlock(hdev);
1008*d75632d0SBastien Nocera return -EINVAL;
1009*d75632d0SBastien Nocera }
1010*d75632d0SBastien Nocera
10113a5c82b7SMarcel Holtmann hdev->le_adv_min_interval = val;
10123a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
10133a5c82b7SMarcel Holtmann
10143a5c82b7SMarcel Holtmann return 0;
10153a5c82b7SMarcel Holtmann }
10163a5c82b7SMarcel Holtmann
adv_min_interval_get(void * data,u64 * val)10173a5c82b7SMarcel Holtmann static int adv_min_interval_get(void *data, u64 *val)
10183a5c82b7SMarcel Holtmann {
10193a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
10203a5c82b7SMarcel Holtmann
10213a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
10223a5c82b7SMarcel Holtmann *val = hdev->le_adv_min_interval;
10233a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
10243a5c82b7SMarcel Holtmann
10253a5c82b7SMarcel Holtmann return 0;
10263a5c82b7SMarcel Holtmann }
10273a5c82b7SMarcel Holtmann
1028231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get,
10293a5c82b7SMarcel Holtmann adv_min_interval_set, "%llu\n");
10303a5c82b7SMarcel Holtmann
adv_max_interval_set(void * data,u64 val)10313a5c82b7SMarcel Holtmann static int adv_max_interval_set(void *data, u64 val)
10323a5c82b7SMarcel Holtmann {
10333a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
10343a5c82b7SMarcel Holtmann
10353a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
1036*d75632d0SBastien Nocera if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) {
1037*d75632d0SBastien Nocera hci_dev_unlock(hdev);
1038*d75632d0SBastien Nocera return -EINVAL;
1039*d75632d0SBastien Nocera }
1040*d75632d0SBastien Nocera
10413a5c82b7SMarcel Holtmann hdev->le_adv_max_interval = val;
10423a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
10433a5c82b7SMarcel Holtmann
10443a5c82b7SMarcel Holtmann return 0;
10453a5c82b7SMarcel Holtmann }
10463a5c82b7SMarcel Holtmann
adv_max_interval_get(void * data,u64 * val)10473a5c82b7SMarcel Holtmann static int adv_max_interval_get(void *data, u64 *val)
10483a5c82b7SMarcel Holtmann {
10493a5c82b7SMarcel Holtmann struct hci_dev *hdev = data;
10503a5c82b7SMarcel Holtmann
10513a5c82b7SMarcel Holtmann hci_dev_lock(hdev);
10523a5c82b7SMarcel Holtmann *val = hdev->le_adv_max_interval;
10533a5c82b7SMarcel Holtmann hci_dev_unlock(hdev);
10543a5c82b7SMarcel Holtmann
10553a5c82b7SMarcel Holtmann return 0;
10563a5c82b7SMarcel Holtmann }
10573a5c82b7SMarcel Holtmann
1058231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get,
10593a5c82b7SMarcel Holtmann adv_max_interval_set, "%llu\n");
10603a5c82b7SMarcel Holtmann
min_key_size_set(void * data,u64 val)106118f81241SMarcel Holtmann static int min_key_size_set(void *data, u64 val)
106218f81241SMarcel Holtmann {
106318f81241SMarcel Holtmann struct hci_dev *hdev = data;
106418f81241SMarcel Holtmann
106518f81241SMarcel Holtmann hci_dev_lock(hdev);
1066f56e715eSGui-Dong Han if (val > hdev->le_max_key_size || val < SMP_MIN_ENC_KEY_SIZE) {
1067f56e715eSGui-Dong Han hci_dev_unlock(hdev);
1068f56e715eSGui-Dong Han return -EINVAL;
1069f56e715eSGui-Dong Han }
1070f56e715eSGui-Dong Han
107118f81241SMarcel Holtmann hdev->le_min_key_size = val;
107218f81241SMarcel Holtmann hci_dev_unlock(hdev);
107318f81241SMarcel Holtmann
107418f81241SMarcel Holtmann return 0;
107518f81241SMarcel Holtmann }
107618f81241SMarcel Holtmann
min_key_size_get(void * data,u64 * val)107718f81241SMarcel Holtmann static int min_key_size_get(void *data, u64 *val)
107818f81241SMarcel Holtmann {
107918f81241SMarcel Holtmann struct hci_dev *hdev = data;
108018f81241SMarcel Holtmann
108118f81241SMarcel Holtmann hci_dev_lock(hdev);
108218f81241SMarcel Holtmann *val = hdev->le_min_key_size;
108318f81241SMarcel Holtmann hci_dev_unlock(hdev);
108418f81241SMarcel Holtmann
108518f81241SMarcel Holtmann return 0;
108618f81241SMarcel Holtmann }
108718f81241SMarcel Holtmann
1088231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(min_key_size_fops, min_key_size_get,
108918f81241SMarcel Holtmann min_key_size_set, "%llu\n");
109018f81241SMarcel Holtmann
max_key_size_set(void * data,u64 val)109118f81241SMarcel Holtmann static int max_key_size_set(void *data, u64 val)
109218f81241SMarcel Holtmann {
109318f81241SMarcel Holtmann struct hci_dev *hdev = data;
109418f81241SMarcel Holtmann
109518f81241SMarcel Holtmann hci_dev_lock(hdev);
1096f56e715eSGui-Dong Han if (val > SMP_MAX_ENC_KEY_SIZE || val < hdev->le_min_key_size) {
1097f56e715eSGui-Dong Han hci_dev_unlock(hdev);
1098f56e715eSGui-Dong Han return -EINVAL;
1099f56e715eSGui-Dong Han }
1100f56e715eSGui-Dong Han
110118f81241SMarcel Holtmann hdev->le_max_key_size = val;
110218f81241SMarcel Holtmann hci_dev_unlock(hdev);
110318f81241SMarcel Holtmann
110418f81241SMarcel Holtmann return 0;
110518f81241SMarcel Holtmann }
110618f81241SMarcel Holtmann
max_key_size_get(void * data,u64 * val)110718f81241SMarcel Holtmann static int max_key_size_get(void *data, u64 *val)
110818f81241SMarcel Holtmann {
110918f81241SMarcel Holtmann struct hci_dev *hdev = data;
111018f81241SMarcel Holtmann
111118f81241SMarcel Holtmann hci_dev_lock(hdev);
111218f81241SMarcel Holtmann *val = hdev->le_max_key_size;
111318f81241SMarcel Holtmann hci_dev_unlock(hdev);
111418f81241SMarcel Holtmann
111518f81241SMarcel Holtmann return 0;
111618f81241SMarcel Holtmann }
111718f81241SMarcel Holtmann
1118231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(max_key_size_fops, max_key_size_get,
111918f81241SMarcel Holtmann max_key_size_set, "%llu\n");
112018f81241SMarcel Holtmann
auth_payload_timeout_set(void * data,u64 val)1121302975cbSSpoorthi Ravishankar Koppad static int auth_payload_timeout_set(void *data, u64 val)
1122302975cbSSpoorthi Ravishankar Koppad {
1123302975cbSSpoorthi Ravishankar Koppad struct hci_dev *hdev = data;
1124302975cbSSpoorthi Ravishankar Koppad
1125302975cbSSpoorthi Ravishankar Koppad if (val < 0x0001 || val > 0xffff)
1126302975cbSSpoorthi Ravishankar Koppad return -EINVAL;
1127302975cbSSpoorthi Ravishankar Koppad
1128302975cbSSpoorthi Ravishankar Koppad hci_dev_lock(hdev);
1129302975cbSSpoorthi Ravishankar Koppad hdev->auth_payload_timeout = val;
1130302975cbSSpoorthi Ravishankar Koppad hci_dev_unlock(hdev);
1131302975cbSSpoorthi Ravishankar Koppad
1132302975cbSSpoorthi Ravishankar Koppad return 0;
1133302975cbSSpoorthi Ravishankar Koppad }
1134302975cbSSpoorthi Ravishankar Koppad
auth_payload_timeout_get(void * data,u64 * val)1135302975cbSSpoorthi Ravishankar Koppad static int auth_payload_timeout_get(void *data, u64 *val)
1136302975cbSSpoorthi Ravishankar Koppad {
1137302975cbSSpoorthi Ravishankar Koppad struct hci_dev *hdev = data;
1138302975cbSSpoorthi Ravishankar Koppad
1139302975cbSSpoorthi Ravishankar Koppad hci_dev_lock(hdev);
1140302975cbSSpoorthi Ravishankar Koppad *val = hdev->auth_payload_timeout;
1141302975cbSSpoorthi Ravishankar Koppad hci_dev_unlock(hdev);
1142302975cbSSpoorthi Ravishankar Koppad
1143302975cbSSpoorthi Ravishankar Koppad return 0;
1144302975cbSSpoorthi Ravishankar Koppad }
1145302975cbSSpoorthi Ravishankar Koppad
1146231ee8bdSJiapeng Zhong DEFINE_DEBUGFS_ATTRIBUTE(auth_payload_timeout_fops,
1147302975cbSSpoorthi Ravishankar Koppad auth_payload_timeout_get,
1148302975cbSSpoorthi Ravishankar Koppad auth_payload_timeout_set, "%llu\n");
1149302975cbSSpoorthi Ravishankar Koppad
force_no_mitm_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1150c2aa30dbSArchie Pusaka static ssize_t force_no_mitm_read(struct file *file,
1151c2aa30dbSArchie Pusaka char __user *user_buf,
1152c2aa30dbSArchie Pusaka size_t count, loff_t *ppos)
1153c2aa30dbSArchie Pusaka {
1154c2aa30dbSArchie Pusaka struct hci_dev *hdev = file->private_data;
1155c2aa30dbSArchie Pusaka char buf[3];
1156c2aa30dbSArchie Pusaka
1157c2aa30dbSArchie Pusaka buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM) ? 'Y' : 'N';
1158c2aa30dbSArchie Pusaka buf[1] = '\n';
1159c2aa30dbSArchie Pusaka buf[2] = '\0';
1160c2aa30dbSArchie Pusaka return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
1161c2aa30dbSArchie Pusaka }
1162c2aa30dbSArchie Pusaka
force_no_mitm_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1163c2aa30dbSArchie Pusaka static ssize_t force_no_mitm_write(struct file *file,
1164c2aa30dbSArchie Pusaka const char __user *user_buf,
1165c2aa30dbSArchie Pusaka size_t count, loff_t *ppos)
1166c2aa30dbSArchie Pusaka {
1167c2aa30dbSArchie Pusaka struct hci_dev *hdev = file->private_data;
1168c2aa30dbSArchie Pusaka char buf[32];
1169c2aa30dbSArchie Pusaka size_t buf_size = min(count, (sizeof(buf) - 1));
1170c2aa30dbSArchie Pusaka bool enable;
1171c2aa30dbSArchie Pusaka
1172c2aa30dbSArchie Pusaka if (copy_from_user(buf, user_buf, buf_size))
1173c2aa30dbSArchie Pusaka return -EFAULT;
1174c2aa30dbSArchie Pusaka
1175c2aa30dbSArchie Pusaka buf[buf_size] = '\0';
117682eae9dcSChristophe JAILLET if (kstrtobool(buf, &enable))
1177c2aa30dbSArchie Pusaka return -EINVAL;
1178c2aa30dbSArchie Pusaka
1179c2aa30dbSArchie Pusaka if (enable == hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM))
1180c2aa30dbSArchie Pusaka return -EALREADY;
1181c2aa30dbSArchie Pusaka
1182c2aa30dbSArchie Pusaka hci_dev_change_flag(hdev, HCI_FORCE_NO_MITM);
1183c2aa30dbSArchie Pusaka
1184c2aa30dbSArchie Pusaka return count;
1185c2aa30dbSArchie Pusaka }
1186c2aa30dbSArchie Pusaka
1187c2aa30dbSArchie Pusaka static const struct file_operations force_no_mitm_fops = {
1188c2aa30dbSArchie Pusaka .open = simple_open,
1189c2aa30dbSArchie Pusaka .read = force_no_mitm_read,
1190c2aa30dbSArchie Pusaka .write = force_no_mitm_write,
1191c2aa30dbSArchie Pusaka .llseek = default_llseek,
1192c2aa30dbSArchie Pusaka };
1193c2aa30dbSArchie Pusaka
1194b55d1abfSJakub Pawlowski DEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter,
1195b55d1abfSJakub Pawlowski HCI_QUIRK_STRICT_DUPLICATE_FILTER);
1196b55d1abfSJakub Pawlowski DEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery,
1197b55d1abfSJakub Pawlowski HCI_QUIRK_SIMULTANEOUS_DISCOVERY);
1198b55d1abfSJakub Pawlowski
hci_debugfs_create_le(struct hci_dev * hdev)119960c5f5fbSMarcel Holtmann void hci_debugfs_create_le(struct hci_dev *hdev)
120060c5f5fbSMarcel Holtmann {
12013a5c82b7SMarcel Holtmann debugfs_create_file("identity", 0400, hdev->debugfs, hdev,
12023a5c82b7SMarcel Holtmann &identity_fops);
12033a5c82b7SMarcel Holtmann debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, hdev,
12043a5c82b7SMarcel Holtmann &rpa_timeout_fops);
12053a5c82b7SMarcel Holtmann debugfs_create_file("random_address", 0444, hdev->debugfs, hdev,
12063a5c82b7SMarcel Holtmann &random_address_fops);
12073a5c82b7SMarcel Holtmann debugfs_create_file("static_address", 0444, hdev->debugfs, hdev,
12083a5c82b7SMarcel Holtmann &static_address_fops);
12093a5c82b7SMarcel Holtmann
12103a5c82b7SMarcel Holtmann /* For controllers with a public address, provide a debug
12113a5c82b7SMarcel Holtmann * option to force the usage of the configured static
12123a5c82b7SMarcel Holtmann * address. By default the public address is used.
12133a5c82b7SMarcel Holtmann */
12143a5c82b7SMarcel Holtmann if (bacmp(&hdev->bdaddr, BDADDR_ANY))
12153a5c82b7SMarcel Holtmann debugfs_create_file("force_static_address", 0644,
12163a5c82b7SMarcel Holtmann hdev->debugfs, hdev,
12173a5c82b7SMarcel Holtmann &force_static_address_fops);
12183a5c82b7SMarcel Holtmann
12193a5c82b7SMarcel Holtmann debugfs_create_u8("white_list_size", 0444, hdev->debugfs,
12203d4f9c00SArchie Pusaka &hdev->le_accept_list_size);
12213a5c82b7SMarcel Holtmann debugfs_create_file("white_list", 0444, hdev->debugfs, hdev,
12223a5c82b7SMarcel Holtmann &white_list_fops);
1223cfdb0c2dSAnkit Navik debugfs_create_u8("resolv_list_size", 0444, hdev->debugfs,
1224cfdb0c2dSAnkit Navik &hdev->le_resolv_list_size);
1225cfdb0c2dSAnkit Navik debugfs_create_file("resolv_list", 0444, hdev->debugfs, hdev,
1226cfdb0c2dSAnkit Navik &resolv_list_fops);
12273a5c82b7SMarcel Holtmann debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs,
12283a5c82b7SMarcel Holtmann hdev, &identity_resolving_keys_fops);
12293a5c82b7SMarcel Holtmann debugfs_create_file("long_term_keys", 0400, hdev->debugfs, hdev,
12303a5c82b7SMarcel Holtmann &long_term_keys_fops);
12313a5c82b7SMarcel Holtmann debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, hdev,
12323a5c82b7SMarcel Holtmann &conn_min_interval_fops);
12333a5c82b7SMarcel Holtmann debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev,
12343a5c82b7SMarcel Holtmann &conn_max_interval_fops);
12353a5c82b7SMarcel Holtmann debugfs_create_file("conn_latency", 0644, hdev->debugfs, hdev,
12363a5c82b7SMarcel Holtmann &conn_latency_fops);
12373a5c82b7SMarcel Holtmann debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, hdev,
12383a5c82b7SMarcel Holtmann &supervision_timeout_fops);
12393a5c82b7SMarcel Holtmann debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev,
12403a5c82b7SMarcel Holtmann &adv_channel_map_fops);
12413a5c82b7SMarcel Holtmann debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, hdev,
12423a5c82b7SMarcel Holtmann &adv_min_interval_fops);
12433a5c82b7SMarcel Holtmann debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, hdev,
12443a5c82b7SMarcel Holtmann &adv_max_interval_fops);
12453a5c82b7SMarcel Holtmann debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs,
12463a5c82b7SMarcel Holtmann &hdev->discov_interleaved_timeout);
124718f81241SMarcel Holtmann debugfs_create_file("min_key_size", 0644, hdev->debugfs, hdev,
124818f81241SMarcel Holtmann &min_key_size_fops);
124918f81241SMarcel Holtmann debugfs_create_file("max_key_size", 0644, hdev->debugfs, hdev,
125018f81241SMarcel Holtmann &max_key_size_fops);
1251302975cbSSpoorthi Ravishankar Koppad debugfs_create_file("auth_payload_timeout", 0644, hdev->debugfs, hdev,
1252302975cbSSpoorthi Ravishankar Koppad &auth_payload_timeout_fops);
1253c2aa30dbSArchie Pusaka debugfs_create_file("force_no_mitm", 0644, hdev->debugfs, hdev,
1254c2aa30dbSArchie Pusaka &force_no_mitm_fops);
1255b55d1abfSJakub Pawlowski
1256b55d1abfSJakub Pawlowski debugfs_create_file("quirk_strict_duplicate_filter", 0644,
1257b55d1abfSJakub Pawlowski hdev->debugfs, hdev,
1258b55d1abfSJakub Pawlowski &quirk_strict_duplicate_filter_fops);
1259b55d1abfSJakub Pawlowski debugfs_create_file("quirk_simultaneous_discovery", 0644,
1260b55d1abfSJakub Pawlowski hdev->debugfs, hdev,
1261b55d1abfSJakub Pawlowski &quirk_simultaneous_discovery_fops);
126260c5f5fbSMarcel Holtmann }
126323b9ceb7SMarcel Holtmann
hci_debugfs_create_conn(struct hci_conn * conn)126423b9ceb7SMarcel Holtmann void hci_debugfs_create_conn(struct hci_conn *conn)
126523b9ceb7SMarcel Holtmann {
126623b9ceb7SMarcel Holtmann struct hci_dev *hdev = conn->hdev;
126723b9ceb7SMarcel Holtmann char name[6];
126823b9ceb7SMarcel Holtmann
12697096dabaSLuiz Augusto von Dentz if (IS_ERR_OR_NULL(hdev->debugfs) || conn->debugfs)
127023b9ceb7SMarcel Holtmann return;
127123b9ceb7SMarcel Holtmann
127223b9ceb7SMarcel Holtmann snprintf(name, sizeof(name), "%u", conn->handle);
127323b9ceb7SMarcel Holtmann conn->debugfs = debugfs_create_dir(name, hdev->debugfs);
127423b9ceb7SMarcel Holtmann }
12758331dc48SLuiz Augusto von Dentz
dut_mode_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)12768331dc48SLuiz Augusto von Dentz static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
12778331dc48SLuiz Augusto von Dentz size_t count, loff_t *ppos)
12788331dc48SLuiz Augusto von Dentz {
12798331dc48SLuiz Augusto von Dentz struct hci_dev *hdev = file->private_data;
12808331dc48SLuiz Augusto von Dentz char buf[3];
12818331dc48SLuiz Augusto von Dentz
12828331dc48SLuiz Augusto von Dentz buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N';
12838331dc48SLuiz Augusto von Dentz buf[1] = '\n';
12848331dc48SLuiz Augusto von Dentz buf[2] = '\0';
12858331dc48SLuiz Augusto von Dentz return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
12868331dc48SLuiz Augusto von Dentz }
12878331dc48SLuiz Augusto von Dentz
dut_mode_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)12888331dc48SLuiz Augusto von Dentz static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
12898331dc48SLuiz Augusto von Dentz size_t count, loff_t *ppos)
12908331dc48SLuiz Augusto von Dentz {
12918331dc48SLuiz Augusto von Dentz struct hci_dev *hdev = file->private_data;
12928331dc48SLuiz Augusto von Dentz struct sk_buff *skb;
12938331dc48SLuiz Augusto von Dentz bool enable;
12948331dc48SLuiz Augusto von Dentz int err;
12958331dc48SLuiz Augusto von Dentz
12968331dc48SLuiz Augusto von Dentz if (!test_bit(HCI_UP, &hdev->flags))
12978331dc48SLuiz Augusto von Dentz return -ENETDOWN;
12988331dc48SLuiz Augusto von Dentz
12998331dc48SLuiz Augusto von Dentz err = kstrtobool_from_user(user_buf, count, &enable);
13008331dc48SLuiz Augusto von Dentz if (err)
13018331dc48SLuiz Augusto von Dentz return err;
13028331dc48SLuiz Augusto von Dentz
13038331dc48SLuiz Augusto von Dentz if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE))
13048331dc48SLuiz Augusto von Dentz return -EALREADY;
13058331dc48SLuiz Augusto von Dentz
13068331dc48SLuiz Augusto von Dentz hci_req_sync_lock(hdev);
13078331dc48SLuiz Augusto von Dentz if (enable)
13088331dc48SLuiz Augusto von Dentz skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL,
13098331dc48SLuiz Augusto von Dentz HCI_CMD_TIMEOUT);
13108331dc48SLuiz Augusto von Dentz else
13118331dc48SLuiz Augusto von Dentz skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
13128331dc48SLuiz Augusto von Dentz HCI_CMD_TIMEOUT);
13138331dc48SLuiz Augusto von Dentz hci_req_sync_unlock(hdev);
13148331dc48SLuiz Augusto von Dentz
13158331dc48SLuiz Augusto von Dentz if (IS_ERR(skb))
13168331dc48SLuiz Augusto von Dentz return PTR_ERR(skb);
13178331dc48SLuiz Augusto von Dentz
13188331dc48SLuiz Augusto von Dentz kfree_skb(skb);
13198331dc48SLuiz Augusto von Dentz
13208331dc48SLuiz Augusto von Dentz hci_dev_change_flag(hdev, HCI_DUT_MODE);
13218331dc48SLuiz Augusto von Dentz
13228331dc48SLuiz Augusto von Dentz return count;
13238331dc48SLuiz Augusto von Dentz }
13248331dc48SLuiz Augusto von Dentz
13258331dc48SLuiz Augusto von Dentz static const struct file_operations dut_mode_fops = {
13268331dc48SLuiz Augusto von Dentz .open = simple_open,
13278331dc48SLuiz Augusto von Dentz .read = dut_mode_read,
13288331dc48SLuiz Augusto von Dentz .write = dut_mode_write,
13298331dc48SLuiz Augusto von Dentz .llseek = default_llseek,
13308331dc48SLuiz Augusto von Dentz };
13318331dc48SLuiz Augusto von Dentz
vendor_diag_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)13328331dc48SLuiz Augusto von Dentz static ssize_t vendor_diag_read(struct file *file, char __user *user_buf,
13338331dc48SLuiz Augusto von Dentz size_t count, loff_t *ppos)
13348331dc48SLuiz Augusto von Dentz {
13358331dc48SLuiz Augusto von Dentz struct hci_dev *hdev = file->private_data;
13368331dc48SLuiz Augusto von Dentz char buf[3];
13378331dc48SLuiz Augusto von Dentz
13388331dc48SLuiz Augusto von Dentz buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N';
13398331dc48SLuiz Augusto von Dentz buf[1] = '\n';
13408331dc48SLuiz Augusto von Dentz buf[2] = '\0';
13418331dc48SLuiz Augusto von Dentz return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
13428331dc48SLuiz Augusto von Dentz }
13438331dc48SLuiz Augusto von Dentz
vendor_diag_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)13448331dc48SLuiz Augusto von Dentz static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
13458331dc48SLuiz Augusto von Dentz size_t count, loff_t *ppos)
13468331dc48SLuiz Augusto von Dentz {
13478331dc48SLuiz Augusto von Dentz struct hci_dev *hdev = file->private_data;
13488331dc48SLuiz Augusto von Dentz bool enable;
13498331dc48SLuiz Augusto von Dentz int err;
13508331dc48SLuiz Augusto von Dentz
13518331dc48SLuiz Augusto von Dentz err = kstrtobool_from_user(user_buf, count, &enable);
13528331dc48SLuiz Augusto von Dentz if (err)
13538331dc48SLuiz Augusto von Dentz return err;
13548331dc48SLuiz Augusto von Dentz
13558331dc48SLuiz Augusto von Dentz /* When the diagnostic flags are not persistent and the transport
13568331dc48SLuiz Augusto von Dentz * is not active or in user channel operation, then there is no need
13578331dc48SLuiz Augusto von Dentz * for the vendor callback. Instead just store the desired value and
13588331dc48SLuiz Augusto von Dentz * the setting will be programmed when the controller gets powered on.
13598331dc48SLuiz Augusto von Dentz */
13608331dc48SLuiz Augusto von Dentz if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
13618331dc48SLuiz Augusto von Dentz (!test_bit(HCI_RUNNING, &hdev->flags) ||
13628331dc48SLuiz Augusto von Dentz hci_dev_test_flag(hdev, HCI_USER_CHANNEL)))
13638331dc48SLuiz Augusto von Dentz goto done;
13648331dc48SLuiz Augusto von Dentz
13658331dc48SLuiz Augusto von Dentz hci_req_sync_lock(hdev);
13668331dc48SLuiz Augusto von Dentz err = hdev->set_diag(hdev, enable);
13678331dc48SLuiz Augusto von Dentz hci_req_sync_unlock(hdev);
13688331dc48SLuiz Augusto von Dentz
13698331dc48SLuiz Augusto von Dentz if (err < 0)
13708331dc48SLuiz Augusto von Dentz return err;
13718331dc48SLuiz Augusto von Dentz
13728331dc48SLuiz Augusto von Dentz done:
13738331dc48SLuiz Augusto von Dentz if (enable)
13748331dc48SLuiz Augusto von Dentz hci_dev_set_flag(hdev, HCI_VENDOR_DIAG);
13758331dc48SLuiz Augusto von Dentz else
13768331dc48SLuiz Augusto von Dentz hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG);
13778331dc48SLuiz Augusto von Dentz
13788331dc48SLuiz Augusto von Dentz return count;
13798331dc48SLuiz Augusto von Dentz }
13808331dc48SLuiz Augusto von Dentz
13818331dc48SLuiz Augusto von Dentz static const struct file_operations vendor_diag_fops = {
13828331dc48SLuiz Augusto von Dentz .open = simple_open,
13838331dc48SLuiz Augusto von Dentz .read = vendor_diag_read,
13848331dc48SLuiz Augusto von Dentz .write = vendor_diag_write,
13858331dc48SLuiz Augusto von Dentz .llseek = default_llseek,
13868331dc48SLuiz Augusto von Dentz };
13878331dc48SLuiz Augusto von Dentz
hci_debugfs_create_basic(struct hci_dev * hdev)13888331dc48SLuiz Augusto von Dentz void hci_debugfs_create_basic(struct hci_dev *hdev)
13898331dc48SLuiz Augusto von Dentz {
13908331dc48SLuiz Augusto von Dentz debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
13918331dc48SLuiz Augusto von Dentz &dut_mode_fops);
13928331dc48SLuiz Augusto von Dentz
13938331dc48SLuiz Augusto von Dentz if (hdev->set_diag)
13948331dc48SLuiz Augusto von Dentz debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev,
13958331dc48SLuiz Augusto von Dentz &vendor_diag_fops);
13968331dc48SLuiz Augusto von Dentz }
1397