// SPDX-License-Identifier: GPL-2.0/* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.*/ #include <linux/debugfs.h>#include <linux/kstrtox.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h> #include "smp.h"#include "hci_debugfs.h" #define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \static ssize_t __name ## _read(struct file *file, \ char __user *user_buf, \ size_t count, loff_t *ppos) \{ \ struct hci_dev *hdev = file->private_data; \ char buf[3]; \ \ buf[0] = test_bit(__quirk, hdev->quirk_flags) ? 'Y' : 'N'; \ buf[1] = '\n'; \ buf[2] = '\0'; \ return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \} \ \static ssize_t __name ## _write(struct file *file, \ const char __user *user_buf, \ size_t count, loff_t *ppos) \{ \ struct hci_dev *hdev = file->private_data; \ bool enable; \ int err; \ \ if (test_bit(HCI_UP, &hdev->flags)) \ return -EBUSY; \ \ err = kstrtobool_from_user(user_buf, count, &enable); \ if (err) \ return err; \ \ if (enable == test_bit(__quirk, hdev->quirk_flags)) \ return -EALREADY; \ \ change_bit(__quirk, hdev->quirk_flags); \ \ return count; \} \ \static const struct file_operations __name ## _fops = { \ .open = simple_open, \ .read = __name ## _read, \ .write = __name ## _write, \ .llseek = default_llseek, \} \ #define DEFINE_INFO_ATTRIBUTE(__name, __field) \static int __name ## _show(struct seq_file *f, void *ptr) \{ \ struct hci_dev *hdev = f->private; \ \ hci_dev_lock(hdev); \ seq_printf(f, "%s\n", hdev->__field ? : ""); \ hci_dev_unlock(hdev); \ \ return 0; \} \ \DEFINE_SHOW_ATTRIBUTE(__name) static int features_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; u8 p; hci_dev_lock(hdev); for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]); if (lmp_le_capable(hdev)) seq_printf(f, "LE: %8ph\n", hdev->le_features); hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(features); static int device_id_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; hci_dev_lock(hdev); seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source, hdev->devid_vendor, hdev->devid_product, hdev->devid_version); hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(device_id); static int device_list_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; struct hci_conn_params *p; struct bdaddr_list *b; hci_dev_lock(hdev); list_for_each_entry(b, &hdev->accept_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); list_for_each_entry(p, &hdev->le_conn_params, list) { seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type, p->auto_connect); } hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(device_list); static int blacklist_show(struct seq_file *f, void *p){ struct hci_dev *hdev = f->private; struct bdaddr_list *b; hci_dev_lock(hdev); list_for_each_entry(b, &hdev->reject_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(blacklist); static int blocked_keys_show(struct seq_file *f, void *p){ struct hci_dev *hdev = f->private; struct blocked_key *key; rcu_read_lock(); list_for_each_entry_rcu(key, &hdev->blocked_keys, list) seq_printf(f, "%u %*phN\n", key->type, 16, key->val); rcu_read_unlock(); return 0;} DEFINE_SHOW_ATTRIBUTE(blocked_keys); static int uuids_show(struct seq_file *f, void *p){ struct hci_dev *hdev = f->private; struct bt_uuid *uuid; hci_dev_lock(hdev); list_for_each_entry(uuid, &hdev->uuids, list) { u8 i, val[16]; /* The Bluetooth UUID values are stored in big endian, * but with reversed byte order. So convert them into * the right order for the %pUb modifier. */ for (i = 0; i < 16; i++) val[i] = uuid->uuid[15 - i]; seq_printf(f, "%pUb\n", val); } hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(uuids); static int remote_oob_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; struct oob_data *data; hci_dev_lock(hdev); list_for_each_entry(data, &hdev->remote_oob_data, list) { seq_printf(f, "%pMR (type %u) %u %*phN %*phN %*phN %*phN\n", &data->bdaddr, data->bdaddr_type, data->present, 16, data->hash192, 16, data->rand192, 16, data->hash256, 16, data->rand256); } hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(remote_oob); static int conn_info_min_age_set(void *data, u64 val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); if (val == 0 || val > hdev->conn_info_max_age) { hci_dev_unlock(hdev); return -EINVAL; } hdev->conn_info_min_age = val; hci_dev_unlock(hdev); return 0;} static int conn_info_min_age_get(void *data, u64 *val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->conn_info_min_age; hci_dev_unlock(hdev); return 0;} DEFINE_DEBUGFS_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get, conn_info_min_age_set, "%llu\n"); static int conn_info_max_age_set(void *data, u64 val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); if (val == 0 || val < hdev->conn_info_min_age) { hci_dev_unlock(hdev); return -EINVAL; } hdev->conn_info_max_age = val; hci_dev_unlock(hdev); return 0;} static int conn_info_max_age_get(void *data, u64 *val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->conn_info_max_age; hci_dev_unlock(hdev); return 0;} DEFINE_DEBUGFS_ATTRIBUTE(conn_info_max_age_fops, conn_info_max_age_get, conn_info_max_age_set, "%llu\n"); static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos){ struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2);} static const struct file_operations use_debug_keys_fops = { .open = simple_open, .read = use_debug_keys_read, .llseek = default_llseek,}; static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos){ struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2);} static const struct file_operations sc_only_mode_fops = { .open = simple_open, .read = sc_only_mode_read, .llseek = default_llseek,}; DEFINE_INFO_ATTRIBUTE(hardware_info, hw_info);DEFINE_INFO_ATTRIBUTE(firmware_info, fw_info); void hci_debugfs_create_common(struct hci_dev *hdev){ debugfs_create_file("features", 0444, hdev->debugfs, hdev, &features_fops); debugfs_create_u16("manufacturer", 0444, hdev->debugfs, &hdev->manufacturer); debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver); debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); debugfs_create_u8("hardware_error", 0444, hdev->debugfs, &hdev->hw_error_code); debugfs_create_file("device_id", 0444, hdev->debugfs, hdev, &device_id_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, &device_list_fops); debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, &blacklist_fops); debugfs_create_file("blocked_keys", 0444, hdev->debugfs, hdev, &blocked_keys_fops); debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); debugfs_create_file("remote_oob", 0400, hdev->debugfs, hdev, &remote_oob_fops); debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, &conn_info_min_age_fops); debugfs_create_file("conn_info_max_age", 0644, hdev->debugfs, hdev, &conn_info_max_age_fops); if (lmp_ssp_capable(hdev) || lmp_le_capable(hdev)) debugfs_create_file("use_debug_keys", 0444, hdev->debugfs, hdev, &use_debug_keys_fops); if (lmp_sc_capable(hdev) || lmp_le_capable(hdev)) debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, hdev, &sc_only_mode_fops); if (hdev->hw_info) debugfs_create_file("hardware_info", 0444, hdev->debugfs, hdev, &hardware_info_fops); if (hdev->fw_info) debugfs_create_file("firmware_info", 0444, hdev->debugfs, hdev, &firmware_info_fops);} static int inquiry_cache_show(struct seq_file *f, void *p){ struct hci_dev *hdev = f->private; struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; hci_dev_lock(hdev); list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", &data->bdaddr, data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, data->dev_class[2], data->dev_class[1], data->dev_class[0], __le16_to_cpu(data->clock_offset), data->rssi, data->ssp_mode, e->timestamp); } hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(inquiry_cache); static int link_keys_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; struct link_key *key; rcu_read_lock(); list_for_each_entry_rcu(key, &hdev->link_keys, list) seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type, HCI_LINK_KEY_SIZE, key->val, key->pin_len); rcu_read_unlock(); return 0;} DEFINE_SHOW_ATTRIBUTE(link_keys); static int dev_class_show(struct seq_file *f, void *ptr){ struct hci_dev *hdev = f->private; hci_dev_lock(hdev); seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); hci_dev_unlock(hdev); return 0;} DEFINE_SHOW_ATTRIBUTE(dev_class); static int voice_setting_get(void *data, u64 *val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->voice_setting; hci_dev_unlock(hdev); return 0;} DEFINE_DEBUGFS_ATTRIBUTE(voice_setting_fops, voice_setting_get, NULL, "0x%4.4llx\n"); static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos){ struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hdev->ssp_debug_mode ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2);} static const struct file_operations ssp_debug_mode_fops = { .open = simple_open, .read = ssp_debug_mode_read, .llseek = default_llseek,}; static int auto_accept_delay_set(void *data, u64 val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); hdev->auto_accept_delay = val; hci_dev_unlock(hdev); return 0;} static int min_encrypt_key_size_set(void *data, u64 val){ struct hci_dev *hdev = data; if (val < 1 || val > 16) return -EINVAL; hci_dev_lock(hdev); hdev->min_enc_key_size = val; hci_dev_unlock(hdev); return 0;} static int min_encrypt_key_size_get(void *data, u64 *val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->min_enc_key_size; hci_dev_unlock(hdev); return 0;} DEFINE_DEBUGFS_ATTRIBUTE(min_encrypt_key_size_fops, min_encrypt_key_size_get, min_encrypt_key_size_set, "%llu\n"); static int auto_accept_delay_get(void *data, u64 *val){ struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->auto_accept_delay; hci_dev_unlock(hdev); return 0;} DEFINE_DEBUGFS_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, auto_accept_delay_set, "%llu\n"); static ssize_t force_bredr_smp_read(struct file *file, char __user *user_buf,Lines 1–500 of 1388. Load more
// SPDX-License-Identifier: GPL-2.0 /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2014 Intel Corporation THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ #include <linux/debugfs.h> #include <linux/kstrtox.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "smp.h" #include "hci_debugfs.h" #define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \ static ssize_t __name ## _read(struct file *file, \ char __user *user_buf, \ size_t count, loff_t *ppos) \ { \ struct hci_dev *hdev = file->private_data; \ char buf[3]; \ \ buf[0] = test_bit(__quirk, hdev->quirk_flags) ? 'Y' : 'N'; \ buf[1] = '\n'; \ buf[2] = '\0'; \ return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \ } \ \ static ssize_t __name ## _write(struct file *file, \ const char __user *user_buf, \ size_t count, loff_t *ppos) \ { \ struct hci_dev *hdev = file->private_data; \ bool enable; \ int err; \ \ if (test_bit(HCI_UP, &hdev->flags)) \ return -EBUSY; \ \ err = kstrtobool_from_user(user_buf, count, &enable); \ if (err) \ return err; \ \ if (enable == test_bit(__quirk, hdev->quirk_flags)) \ return -EALREADY; \ \ change_bit(__quirk, hdev->quirk_flags); \ \ return count; \ } \ \ static const struct file_operations __name ## _fops = { \ .open = simple_open, \ .read = __name ## _read, \ .write = __name ## _write, \ .llseek = default_llseek, \ } \ #define DEFINE_INFO_ATTRIBUTE(__name, __field) \ static int __name ## _show(struct seq_file *f, void *ptr) \ { \ struct hci_dev *hdev = f->private; \ \ hci_dev_lock(hdev); \ seq_printf(f, "%s\n", hdev->__field ? : ""); \ hci_dev_unlock(hdev); \ \ return 0; \ } \ \ DEFINE_SHOW_ATTRIBUTE(__name) static int features_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; u8 p; hci_dev_lock(hdev); for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]); if (lmp_le_capable(hdev)) seq_printf(f, "LE: %8ph\n", hdev->le_features); hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(features); static int device_id_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; hci_dev_lock(hdev); seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source, hdev->devid_vendor, hdev->devid_product, hdev->devid_version); hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(device_id); static int device_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct hci_conn_params *p; struct bdaddr_list *b; hci_dev_lock(hdev); list_for_each_entry(b, &hdev->accept_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); list_for_each_entry(p, &hdev->le_conn_params, list) { seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type, p->auto_connect); } hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(device_list); static int blacklist_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct bdaddr_list *b; hci_dev_lock(hdev); list_for_each_entry(b, &hdev->reject_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(blacklist); static int blocked_keys_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct blocked_key *key; rcu_read_lock(); list_for_each_entry_rcu(key, &hdev->blocked_keys, list) seq_printf(f, "%u %*phN\n", key->type, 16, key->val); rcu_read_unlock(); return 0; } DEFINE_SHOW_ATTRIBUTE(blocked_keys); static int uuids_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct bt_uuid *uuid; hci_dev_lock(hdev); list_for_each_entry(uuid, &hdev->uuids, list) { u8 i, val[16]; /* The Bluetooth UUID values are stored in big endian, * but with reversed byte order. So convert them into * the right order for the %pUb modifier. */ for (i = 0; i < 16; i++) val[i] = uuid->uuid[15 - i]; seq_printf(f, "%pUb\n", val); } hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(uuids); static int remote_oob_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct oob_data *data; hci_dev_lock(hdev); list_for_each_entry(data, &hdev->remote_oob_data, list) { seq_printf(f, "%pMR (type %u) %u %*phN %*phN %*phN %*phN\n", &data->bdaddr, data->bdaddr_type, data->present, 16, data->hash192, 16, data->rand192, 16, data->hash256, 16, data->rand256); } hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(remote_oob); static int conn_info_min_age_set(void *data, u64 val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); if (val == 0 || val > hdev->conn_info_max_age) { hci_dev_unlock(hdev); return -EINVAL; } hdev->conn_info_min_age = val; hci_dev_unlock(hdev); return 0; } static int conn_info_min_age_get(void *data, u64 *val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->conn_info_min_age; hci_dev_unlock(hdev); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get, conn_info_min_age_set, "%llu\n"); static int conn_info_max_age_set(void *data, u64 val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); if (val == 0 || val < hdev->conn_info_min_age) { hci_dev_unlock(hdev); return -EINVAL; } hdev->conn_info_max_age = val; hci_dev_unlock(hdev); return 0; } static int conn_info_max_age_get(void *data, u64 *val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->conn_info_max_age; hci_dev_unlock(hdev); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(conn_info_max_age_fops, conn_info_max_age_get, conn_info_max_age_set, "%llu\n"); static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } static const struct file_operations use_debug_keys_fops = { .open = simple_open, .read = use_debug_keys_read, .llseek = default_llseek, }; static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } static const struct file_operations sc_only_mode_fops = { .open = simple_open, .read = sc_only_mode_read, .llseek = default_llseek, }; DEFINE_INFO_ATTRIBUTE(hardware_info, hw_info); DEFINE_INFO_ATTRIBUTE(firmware_info, fw_info); void hci_debugfs_create_common(struct hci_dev *hdev) { debugfs_create_file("features", 0444, hdev->debugfs, hdev, &features_fops); debugfs_create_u16("manufacturer", 0444, hdev->debugfs, &hdev->manufacturer); debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver); debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); debugfs_create_u8("hardware_error", 0444, hdev->debugfs, &hdev->hw_error_code); debugfs_create_file("device_id", 0444, hdev->debugfs, hdev, &device_id_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, &device_list_fops); debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, &blacklist_fops); debugfs_create_file("blocked_keys", 0444, hdev->debugfs, hdev, &blocked_keys_fops); debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); debugfs_create_file("remote_oob", 0400, hdev->debugfs, hdev, &remote_oob_fops); debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, &conn_info_min_age_fops); debugfs_create_file("conn_info_max_age", 0644, hdev->debugfs, hdev, &conn_info_max_age_fops); if (lmp_ssp_capable(hdev) || lmp_le_capable(hdev)) debugfs_create_file("use_debug_keys", 0444, hdev->debugfs, hdev, &use_debug_keys_fops); if (lmp_sc_capable(hdev) || lmp_le_capable(hdev)) debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, hdev, &sc_only_mode_fops); if (hdev->hw_info) debugfs_create_file("hardware_info", 0444, hdev->debugfs, hdev, &hardware_info_fops); if (hdev->fw_info) debugfs_create_file("firmware_info", 0444, hdev->debugfs, hdev, &firmware_info_fops); } static int inquiry_cache_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; hci_dev_lock(hdev); list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", &data->bdaddr, data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, data->dev_class[2], data->dev_class[1], data->dev_class[0], __le16_to_cpu(data->clock_offset), data->rssi, data->ssp_mode, e->timestamp); } hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(inquiry_cache); static int link_keys_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct link_key *key; rcu_read_lock(); list_for_each_entry_rcu(key, &hdev->link_keys, list) seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type, HCI_LINK_KEY_SIZE, key->val, key->pin_len); rcu_read_unlock(); return 0; } DEFINE_SHOW_ATTRIBUTE(link_keys); static int dev_class_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; hci_dev_lock(hdev); seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); hci_dev_unlock(hdev); return 0; } DEFINE_SHOW_ATTRIBUTE(dev_class); static int voice_setting_get(void *data, u64 *val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->voice_setting; hci_dev_unlock(hdev); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(voice_setting_fops, voice_setting_get, NULL, "0x%4.4llx\n"); static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct hci_dev *hdev = file->private_data; char buf[3]; buf[0] = hdev->ssp_debug_mode ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } static const struct file_operations ssp_debug_mode_fops = { .open = simple_open, .read = ssp_debug_mode_read, .llseek = default_llseek, }; static int auto_accept_delay_set(void *data, u64 val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); hdev->auto_accept_delay = val; hci_dev_unlock(hdev); return 0; } static int min_encrypt_key_size_set(void *data, u64 val) { struct hci_dev *hdev = data; if (val < 1 || val > 16) return -EINVAL; hci_dev_lock(hdev); hdev->min_enc_key_size = val; hci_dev_unlock(hdev); return 0; } static int min_encrypt_key_size_get(void *data, u64 *val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->min_enc_key_size; hci_dev_unlock(hdev); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(min_encrypt_key_size_fops, min_encrypt_key_size_get, min_encrypt_key_size_set, "%llu\n"); static int auto_accept_delay_get(void *data, u64 *val) { struct hci_dev *hdev = data; hci_dev_lock(hdev); *val = hdev->auto_accept_delay; hci_dev_unlock(hdev); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, auto_accept_delay_set, "%llu\n"); static ssize_t force_bredr_smp_read(struct file *file, char __user *user_buf,