162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci BlueZ - Bluetooth protocol stack for Linux 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright (C) 2014 Intel Corporation 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci it under the terms of the GNU General Public License version 2 as 862306a36Sopenharmony_ci published by the Free Software Foundation; 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1162306a36Sopenharmony_ci OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1262306a36Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 1362306a36Sopenharmony_ci IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 1462306a36Sopenharmony_ci CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 1562306a36Sopenharmony_ci WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1662306a36Sopenharmony_ci ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1762306a36Sopenharmony_ci OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 2062306a36Sopenharmony_ci COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 2162306a36Sopenharmony_ci SOFTWARE IS DISCLAIMED. 2262306a36Sopenharmony_ci*/ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/debugfs.h> 2562306a36Sopenharmony_ci#include <linux/kstrtox.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 2862306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "smp.h" 3162306a36Sopenharmony_ci#include "hci_request.h" 3262306a36Sopenharmony_ci#include "hci_debugfs.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \ 3562306a36Sopenharmony_cistatic ssize_t __name ## _read(struct file *file, \ 3662306a36Sopenharmony_ci char __user *user_buf, \ 3762306a36Sopenharmony_ci size_t count, loff_t *ppos) \ 3862306a36Sopenharmony_ci{ \ 3962306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; \ 4062306a36Sopenharmony_ci char buf[3]; \ 4162306a36Sopenharmony_ci \ 4262306a36Sopenharmony_ci buf[0] = test_bit(__quirk, &hdev->quirks) ? 'Y' : 'N'; \ 4362306a36Sopenharmony_ci buf[1] = '\n'; \ 4462306a36Sopenharmony_ci buf[2] = '\0'; \ 4562306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \ 4662306a36Sopenharmony_ci} \ 4762306a36Sopenharmony_ci \ 4862306a36Sopenharmony_cistatic ssize_t __name ## _write(struct file *file, \ 4962306a36Sopenharmony_ci const char __user *user_buf, \ 5062306a36Sopenharmony_ci size_t count, loff_t *ppos) \ 5162306a36Sopenharmony_ci{ \ 5262306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; \ 5362306a36Sopenharmony_ci bool enable; \ 5462306a36Sopenharmony_ci int err; \ 5562306a36Sopenharmony_ci \ 5662306a36Sopenharmony_ci if (test_bit(HCI_UP, &hdev->flags)) \ 5762306a36Sopenharmony_ci return -EBUSY; \ 5862306a36Sopenharmony_ci \ 5962306a36Sopenharmony_ci err = kstrtobool_from_user(user_buf, count, &enable); \ 6062306a36Sopenharmony_ci if (err) \ 6162306a36Sopenharmony_ci return err; \ 6262306a36Sopenharmony_ci \ 6362306a36Sopenharmony_ci if (enable == test_bit(__quirk, &hdev->quirks)) \ 6462306a36Sopenharmony_ci return -EALREADY; \ 6562306a36Sopenharmony_ci \ 6662306a36Sopenharmony_ci change_bit(__quirk, &hdev->quirks); \ 6762306a36Sopenharmony_ci \ 6862306a36Sopenharmony_ci return count; \ 6962306a36Sopenharmony_ci} \ 7062306a36Sopenharmony_ci \ 7162306a36Sopenharmony_cistatic const struct file_operations __name ## _fops = { \ 7262306a36Sopenharmony_ci .open = simple_open, \ 7362306a36Sopenharmony_ci .read = __name ## _read, \ 7462306a36Sopenharmony_ci .write = __name ## _write, \ 7562306a36Sopenharmony_ci .llseek = default_llseek, \ 7662306a36Sopenharmony_ci} \ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define DEFINE_INFO_ATTRIBUTE(__name, __field) \ 7962306a36Sopenharmony_cistatic int __name ## _show(struct seq_file *f, void *ptr) \ 8062306a36Sopenharmony_ci{ \ 8162306a36Sopenharmony_ci struct hci_dev *hdev = f->private; \ 8262306a36Sopenharmony_ci \ 8362306a36Sopenharmony_ci hci_dev_lock(hdev); \ 8462306a36Sopenharmony_ci seq_printf(f, "%s\n", hdev->__field ? : ""); \ 8562306a36Sopenharmony_ci hci_dev_unlock(hdev); \ 8662306a36Sopenharmony_ci \ 8762306a36Sopenharmony_ci return 0; \ 8862306a36Sopenharmony_ci} \ 8962306a36Sopenharmony_ci \ 9062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(__name) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int features_show(struct seq_file *f, void *ptr) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 9562306a36Sopenharmony_ci u8 p; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci hci_dev_lock(hdev); 9862306a36Sopenharmony_ci for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) 9962306a36Sopenharmony_ci seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]); 10062306a36Sopenharmony_ci if (lmp_le_capable(hdev)) 10162306a36Sopenharmony_ci seq_printf(f, "LE: %8ph\n", hdev->le_features); 10262306a36Sopenharmony_ci hci_dev_unlock(hdev); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(features); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int device_id_show(struct seq_file *f, void *ptr) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci hci_dev_lock(hdev); 11462306a36Sopenharmony_ci seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source, 11562306a36Sopenharmony_ci hdev->devid_vendor, hdev->devid_product, hdev->devid_version); 11662306a36Sopenharmony_ci hci_dev_unlock(hdev); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(device_id); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int device_list_show(struct seq_file *f, void *ptr) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 12662306a36Sopenharmony_ci struct hci_conn_params *p; 12762306a36Sopenharmony_ci struct bdaddr_list *b; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci hci_dev_lock(hdev); 13062306a36Sopenharmony_ci list_for_each_entry(b, &hdev->accept_list, list) 13162306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); 13262306a36Sopenharmony_ci list_for_each_entry(p, &hdev->le_conn_params, list) { 13362306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type, 13462306a36Sopenharmony_ci p->auto_connect); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci hci_dev_unlock(hdev); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(device_list); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int blacklist_show(struct seq_file *f, void *p) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 14662306a36Sopenharmony_ci struct bdaddr_list *b; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci hci_dev_lock(hdev); 14962306a36Sopenharmony_ci list_for_each_entry(b, &hdev->reject_list, list) 15062306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); 15162306a36Sopenharmony_ci hci_dev_unlock(hdev); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(blacklist); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int blocked_keys_show(struct seq_file *f, void *p) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 16162306a36Sopenharmony_ci struct blocked_key *key; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci rcu_read_lock(); 16462306a36Sopenharmony_ci list_for_each_entry_rcu(key, &hdev->blocked_keys, list) 16562306a36Sopenharmony_ci seq_printf(f, "%u %*phN\n", key->type, 16, key->val); 16662306a36Sopenharmony_ci rcu_read_unlock(); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(blocked_keys); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int uuids_show(struct seq_file *f, void *p) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 17662306a36Sopenharmony_ci struct bt_uuid *uuid; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci hci_dev_lock(hdev); 17962306a36Sopenharmony_ci list_for_each_entry(uuid, &hdev->uuids, list) { 18062306a36Sopenharmony_ci u8 i, val[16]; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* The Bluetooth UUID values are stored in big endian, 18362306a36Sopenharmony_ci * but with reversed byte order. So convert them into 18462306a36Sopenharmony_ci * the right order for the %pUb modifier. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci for (i = 0; i < 16; i++) 18762306a36Sopenharmony_ci val[i] = uuid->uuid[15 - i]; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci seq_printf(f, "%pUb\n", val); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci hci_dev_unlock(hdev); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(uuids); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int remote_oob_show(struct seq_file *f, void *ptr) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 20162306a36Sopenharmony_ci struct oob_data *data; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci hci_dev_lock(hdev); 20462306a36Sopenharmony_ci list_for_each_entry(data, &hdev->remote_oob_data, list) { 20562306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u) %u %*phN %*phN %*phN %*phN\n", 20662306a36Sopenharmony_ci &data->bdaddr, data->bdaddr_type, data->present, 20762306a36Sopenharmony_ci 16, data->hash192, 16, data->rand192, 20862306a36Sopenharmony_ci 16, data->hash256, 16, data->rand256); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci hci_dev_unlock(hdev); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(remote_oob); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int conn_info_min_age_set(void *data, u64 val) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct hci_dev *hdev = data; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (val == 0 || val > hdev->conn_info_max_age) 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci hci_dev_lock(hdev); 22562306a36Sopenharmony_ci hdev->conn_info_min_age = val; 22662306a36Sopenharmony_ci hci_dev_unlock(hdev); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int conn_info_min_age_get(void *data, u64 *val) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct hci_dev *hdev = data; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci hci_dev_lock(hdev); 23662306a36Sopenharmony_ci *val = hdev->conn_info_min_age; 23762306a36Sopenharmony_ci hci_dev_unlock(hdev); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get, 24362306a36Sopenharmony_ci conn_info_min_age_set, "%llu\n"); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int conn_info_max_age_set(void *data, u64 val) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct hci_dev *hdev = data; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (val == 0 || val < hdev->conn_info_min_age) 25062306a36Sopenharmony_ci return -EINVAL; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci hci_dev_lock(hdev); 25362306a36Sopenharmony_ci hdev->conn_info_max_age = val; 25462306a36Sopenharmony_ci hci_dev_unlock(hdev); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int conn_info_max_age_get(void *data, u64 *val) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct hci_dev *hdev = data; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci hci_dev_lock(hdev); 26462306a36Sopenharmony_ci *val = hdev->conn_info_max_age; 26562306a36Sopenharmony_ci hci_dev_unlock(hdev); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(conn_info_max_age_fops, conn_info_max_age_get, 27162306a36Sopenharmony_ci conn_info_max_age_set, "%llu\n"); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, 27462306a36Sopenharmony_ci size_t count, loff_t *ppos) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 27762306a36Sopenharmony_ci char buf[3]; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y' : 'N'; 28062306a36Sopenharmony_ci buf[1] = '\n'; 28162306a36Sopenharmony_ci buf[2] = '\0'; 28262306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic const struct file_operations use_debug_keys_fops = { 28662306a36Sopenharmony_ci .open = simple_open, 28762306a36Sopenharmony_ci .read = use_debug_keys_read, 28862306a36Sopenharmony_ci .llseek = default_llseek, 28962306a36Sopenharmony_ci}; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, 29262306a36Sopenharmony_ci size_t count, loff_t *ppos) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 29562306a36Sopenharmony_ci char buf[3]; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y' : 'N'; 29862306a36Sopenharmony_ci buf[1] = '\n'; 29962306a36Sopenharmony_ci buf[2] = '\0'; 30062306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic const struct file_operations sc_only_mode_fops = { 30462306a36Sopenharmony_ci .open = simple_open, 30562306a36Sopenharmony_ci .read = sc_only_mode_read, 30662306a36Sopenharmony_ci .llseek = default_llseek, 30762306a36Sopenharmony_ci}; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciDEFINE_INFO_ATTRIBUTE(hardware_info, hw_info); 31062306a36Sopenharmony_ciDEFINE_INFO_ATTRIBUTE(firmware_info, fw_info); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_civoid hci_debugfs_create_common(struct hci_dev *hdev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci debugfs_create_file("features", 0444, hdev->debugfs, hdev, 31562306a36Sopenharmony_ci &features_fops); 31662306a36Sopenharmony_ci debugfs_create_u16("manufacturer", 0444, hdev->debugfs, 31762306a36Sopenharmony_ci &hdev->manufacturer); 31862306a36Sopenharmony_ci debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver); 31962306a36Sopenharmony_ci debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); 32062306a36Sopenharmony_ci debugfs_create_u8("hardware_error", 0444, hdev->debugfs, 32162306a36Sopenharmony_ci &hdev->hw_error_code); 32262306a36Sopenharmony_ci debugfs_create_file("device_id", 0444, hdev->debugfs, hdev, 32362306a36Sopenharmony_ci &device_id_fops); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, 32662306a36Sopenharmony_ci &device_list_fops); 32762306a36Sopenharmony_ci debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, 32862306a36Sopenharmony_ci &blacklist_fops); 32962306a36Sopenharmony_ci debugfs_create_file("blocked_keys", 0444, hdev->debugfs, hdev, 33062306a36Sopenharmony_ci &blocked_keys_fops); 33162306a36Sopenharmony_ci debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); 33262306a36Sopenharmony_ci debugfs_create_file("remote_oob", 0400, hdev->debugfs, hdev, 33362306a36Sopenharmony_ci &remote_oob_fops); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, 33662306a36Sopenharmony_ci &conn_info_min_age_fops); 33762306a36Sopenharmony_ci debugfs_create_file("conn_info_max_age", 0644, hdev->debugfs, hdev, 33862306a36Sopenharmony_ci &conn_info_max_age_fops); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (lmp_ssp_capable(hdev) || lmp_le_capable(hdev)) 34162306a36Sopenharmony_ci debugfs_create_file("use_debug_keys", 0444, hdev->debugfs, 34262306a36Sopenharmony_ci hdev, &use_debug_keys_fops); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (lmp_sc_capable(hdev) || lmp_le_capable(hdev)) 34562306a36Sopenharmony_ci debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, 34662306a36Sopenharmony_ci hdev, &sc_only_mode_fops); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (hdev->hw_info) 34962306a36Sopenharmony_ci debugfs_create_file("hardware_info", 0444, hdev->debugfs, 35062306a36Sopenharmony_ci hdev, &hardware_info_fops); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (hdev->fw_info) 35362306a36Sopenharmony_ci debugfs_create_file("firmware_info", 0444, hdev->debugfs, 35462306a36Sopenharmony_ci hdev, &firmware_info_fops); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int inquiry_cache_show(struct seq_file *f, void *p) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 36062306a36Sopenharmony_ci struct discovery_state *cache = &hdev->discovery; 36162306a36Sopenharmony_ci struct inquiry_entry *e; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci hci_dev_lock(hdev); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci list_for_each_entry(e, &cache->all, all) { 36662306a36Sopenharmony_ci struct inquiry_data *data = &e->data; 36762306a36Sopenharmony_ci seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", 36862306a36Sopenharmony_ci &data->bdaddr, 36962306a36Sopenharmony_ci data->pscan_rep_mode, data->pscan_period_mode, 37062306a36Sopenharmony_ci data->pscan_mode, data->dev_class[2], 37162306a36Sopenharmony_ci data->dev_class[1], data->dev_class[0], 37262306a36Sopenharmony_ci __le16_to_cpu(data->clock_offset), 37362306a36Sopenharmony_ci data->rssi, data->ssp_mode, e->timestamp); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci hci_dev_unlock(hdev); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(inquiry_cache); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int link_keys_show(struct seq_file *f, void *ptr) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 38662306a36Sopenharmony_ci struct link_key *key; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci rcu_read_lock(); 38962306a36Sopenharmony_ci list_for_each_entry_rcu(key, &hdev->link_keys, list) 39062306a36Sopenharmony_ci seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type, 39162306a36Sopenharmony_ci HCI_LINK_KEY_SIZE, key->val, key->pin_len); 39262306a36Sopenharmony_ci rcu_read_unlock(); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(link_keys); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int dev_class_show(struct seq_file *f, void *ptr) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci hci_dev_lock(hdev); 40462306a36Sopenharmony_ci seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], 40562306a36Sopenharmony_ci hdev->dev_class[1], hdev->dev_class[0]); 40662306a36Sopenharmony_ci hci_dev_unlock(hdev); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dev_class); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int voice_setting_get(void *data, u64 *val) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct hci_dev *hdev = data; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci hci_dev_lock(hdev); 41862306a36Sopenharmony_ci *val = hdev->voice_setting; 41962306a36Sopenharmony_ci hci_dev_unlock(hdev); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(voice_setting_fops, voice_setting_get, 42562306a36Sopenharmony_ci NULL, "0x%4.4llx\n"); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf, 42862306a36Sopenharmony_ci size_t count, loff_t *ppos) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 43162306a36Sopenharmony_ci char buf[3]; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci buf[0] = hdev->ssp_debug_mode ? 'Y' : 'N'; 43462306a36Sopenharmony_ci buf[1] = '\n'; 43562306a36Sopenharmony_ci buf[2] = '\0'; 43662306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic const struct file_operations ssp_debug_mode_fops = { 44062306a36Sopenharmony_ci .open = simple_open, 44162306a36Sopenharmony_ci .read = ssp_debug_mode_read, 44262306a36Sopenharmony_ci .llseek = default_llseek, 44362306a36Sopenharmony_ci}; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int auto_accept_delay_set(void *data, u64 val) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct hci_dev *hdev = data; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci hci_dev_lock(hdev); 45062306a36Sopenharmony_ci hdev->auto_accept_delay = val; 45162306a36Sopenharmony_ci hci_dev_unlock(hdev); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int min_encrypt_key_size_set(void *data, u64 val) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct hci_dev *hdev = data; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (val < 1 || val > 16) 46162306a36Sopenharmony_ci return -EINVAL; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci hci_dev_lock(hdev); 46462306a36Sopenharmony_ci hdev->min_enc_key_size = val; 46562306a36Sopenharmony_ci hci_dev_unlock(hdev); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int min_encrypt_key_size_get(void *data, u64 *val) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct hci_dev *hdev = data; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci hci_dev_lock(hdev); 47562306a36Sopenharmony_ci *val = hdev->min_enc_key_size; 47662306a36Sopenharmony_ci hci_dev_unlock(hdev); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(min_encrypt_key_size_fops, 48262306a36Sopenharmony_ci min_encrypt_key_size_get, 48362306a36Sopenharmony_ci min_encrypt_key_size_set, "%llu\n"); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int auto_accept_delay_get(void *data, u64 *val) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct hci_dev *hdev = data; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci hci_dev_lock(hdev); 49062306a36Sopenharmony_ci *val = hdev->auto_accept_delay; 49162306a36Sopenharmony_ci hci_dev_unlock(hdev); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, 49762306a36Sopenharmony_ci auto_accept_delay_set, "%llu\n"); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic ssize_t force_bredr_smp_read(struct file *file, 50062306a36Sopenharmony_ci char __user *user_buf, 50162306a36Sopenharmony_ci size_t count, loff_t *ppos) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 50462306a36Sopenharmony_ci char buf[3]; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP) ? 'Y' : 'N'; 50762306a36Sopenharmony_ci buf[1] = '\n'; 50862306a36Sopenharmony_ci buf[2] = '\0'; 50962306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic ssize_t force_bredr_smp_write(struct file *file, 51362306a36Sopenharmony_ci const char __user *user_buf, 51462306a36Sopenharmony_ci size_t count, loff_t *ppos) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 51762306a36Sopenharmony_ci bool enable; 51862306a36Sopenharmony_ci int err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci err = kstrtobool_from_user(user_buf, count, &enable); 52162306a36Sopenharmony_ci if (err) 52262306a36Sopenharmony_ci return err; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci err = smp_force_bredr(hdev, enable); 52562306a36Sopenharmony_ci if (err) 52662306a36Sopenharmony_ci return err; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return count; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic const struct file_operations force_bredr_smp_fops = { 53262306a36Sopenharmony_ci .open = simple_open, 53362306a36Sopenharmony_ci .read = force_bredr_smp_read, 53462306a36Sopenharmony_ci .write = force_bredr_smp_write, 53562306a36Sopenharmony_ci .llseek = default_llseek, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int idle_timeout_set(void *data, u64 val) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct hci_dev *hdev = data; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (val != 0 && (val < 500 || val > 3600000)) 54362306a36Sopenharmony_ci return -EINVAL; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci hci_dev_lock(hdev); 54662306a36Sopenharmony_ci hdev->idle_timeout = val; 54762306a36Sopenharmony_ci hci_dev_unlock(hdev); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int idle_timeout_get(void *data, u64 *val) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct hci_dev *hdev = data; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci hci_dev_lock(hdev); 55762306a36Sopenharmony_ci *val = hdev->idle_timeout; 55862306a36Sopenharmony_ci hci_dev_unlock(hdev); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(idle_timeout_fops, idle_timeout_get, 56462306a36Sopenharmony_ci idle_timeout_set, "%llu\n"); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic int sniff_min_interval_set(void *data, u64 val) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct hci_dev *hdev = data; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (val == 0 || val % 2 || val > hdev->sniff_max_interval) 57162306a36Sopenharmony_ci return -EINVAL; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci hci_dev_lock(hdev); 57462306a36Sopenharmony_ci hdev->sniff_min_interval = val; 57562306a36Sopenharmony_ci hci_dev_unlock(hdev); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int sniff_min_interval_get(void *data, u64 *val) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct hci_dev *hdev = data; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci hci_dev_lock(hdev); 58562306a36Sopenharmony_ci *val = hdev->sniff_min_interval; 58662306a36Sopenharmony_ci hci_dev_unlock(hdev); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(sniff_min_interval_fops, sniff_min_interval_get, 59262306a36Sopenharmony_ci sniff_min_interval_set, "%llu\n"); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int sniff_max_interval_set(void *data, u64 val) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct hci_dev *hdev = data; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (val == 0 || val % 2 || val < hdev->sniff_min_interval) 59962306a36Sopenharmony_ci return -EINVAL; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci hci_dev_lock(hdev); 60262306a36Sopenharmony_ci hdev->sniff_max_interval = val; 60362306a36Sopenharmony_ci hci_dev_unlock(hdev); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int sniff_max_interval_get(void *data, u64 *val) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct hci_dev *hdev = data; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci hci_dev_lock(hdev); 61362306a36Sopenharmony_ci *val = hdev->sniff_max_interval; 61462306a36Sopenharmony_ci hci_dev_unlock(hdev); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get, 62062306a36Sopenharmony_ci sniff_max_interval_set, "%llu\n"); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_civoid hci_debugfs_create_bredr(struct hci_dev *hdev) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci debugfs_create_file("inquiry_cache", 0444, hdev->debugfs, hdev, 62562306a36Sopenharmony_ci &inquiry_cache_fops); 62662306a36Sopenharmony_ci debugfs_create_file("link_keys", 0400, hdev->debugfs, hdev, 62762306a36Sopenharmony_ci &link_keys_fops); 62862306a36Sopenharmony_ci debugfs_create_file("dev_class", 0444, hdev->debugfs, hdev, 62962306a36Sopenharmony_ci &dev_class_fops); 63062306a36Sopenharmony_ci debugfs_create_file("voice_setting", 0444, hdev->debugfs, hdev, 63162306a36Sopenharmony_ci &voice_setting_fops); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* If the controller does not support BR/EDR Secure Connections 63462306a36Sopenharmony_ci * feature, then the BR/EDR SMP channel shall not be present. 63562306a36Sopenharmony_ci * 63662306a36Sopenharmony_ci * To test this with Bluetooth 4.0 controllers, create a debugfs 63762306a36Sopenharmony_ci * switch that allows forcing BR/EDR SMP support and accepting 63862306a36Sopenharmony_ci * cross-transport pairing on non-AES encrypted connections. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci if (!lmp_sc_capable(hdev)) 64162306a36Sopenharmony_ci debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs, 64262306a36Sopenharmony_ci hdev, &force_bredr_smp_fops); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (lmp_ssp_capable(hdev)) { 64562306a36Sopenharmony_ci debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs, 64662306a36Sopenharmony_ci hdev, &ssp_debug_mode_fops); 64762306a36Sopenharmony_ci debugfs_create_file("min_encrypt_key_size", 0644, hdev->debugfs, 64862306a36Sopenharmony_ci hdev, &min_encrypt_key_size_fops); 64962306a36Sopenharmony_ci debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs, 65062306a36Sopenharmony_ci hdev, &auto_accept_delay_fops); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (lmp_sniff_capable(hdev)) { 65462306a36Sopenharmony_ci debugfs_create_file("idle_timeout", 0644, hdev->debugfs, 65562306a36Sopenharmony_ci hdev, &idle_timeout_fops); 65662306a36Sopenharmony_ci debugfs_create_file("sniff_min_interval", 0644, hdev->debugfs, 65762306a36Sopenharmony_ci hdev, &sniff_min_interval_fops); 65862306a36Sopenharmony_ci debugfs_create_file("sniff_max_interval", 0644, hdev->debugfs, 65962306a36Sopenharmony_ci hdev, &sniff_max_interval_fops); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int identity_show(struct seq_file *f, void *p) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 66662306a36Sopenharmony_ci bdaddr_t addr; 66762306a36Sopenharmony_ci u8 addr_type; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci hci_dev_lock(hdev); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci hci_copy_identity_address(hdev, &addr, &addr_type); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type, 67462306a36Sopenharmony_ci 16, hdev->irk, &hdev->rpa); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci hci_dev_unlock(hdev); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(identity); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int rpa_timeout_set(void *data, u64 val) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct hci_dev *hdev = data; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci /* Require the RPA timeout to be at least 30 seconds and at most 68862306a36Sopenharmony_ci * 24 hours. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci if (val < 30 || val > (60 * 60 * 24)) 69162306a36Sopenharmony_ci return -EINVAL; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci hci_dev_lock(hdev); 69462306a36Sopenharmony_ci hdev->rpa_timeout = val; 69562306a36Sopenharmony_ci hci_dev_unlock(hdev); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int rpa_timeout_get(void *data, u64 *val) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct hci_dev *hdev = data; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci hci_dev_lock(hdev); 70562306a36Sopenharmony_ci *val = hdev->rpa_timeout; 70662306a36Sopenharmony_ci hci_dev_unlock(hdev); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get, 71262306a36Sopenharmony_ci rpa_timeout_set, "%llu\n"); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int random_address_show(struct seq_file *f, void *p) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci hci_dev_lock(hdev); 71962306a36Sopenharmony_ci seq_printf(f, "%pMR\n", &hdev->random_addr); 72062306a36Sopenharmony_ci hci_dev_unlock(hdev); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(random_address); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic int static_address_show(struct seq_file *f, void *p) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci hci_dev_lock(hdev); 73262306a36Sopenharmony_ci seq_printf(f, "%pMR\n", &hdev->static_addr); 73362306a36Sopenharmony_ci hci_dev_unlock(hdev); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(static_address); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic ssize_t force_static_address_read(struct file *file, 74162306a36Sopenharmony_ci char __user *user_buf, 74262306a36Sopenharmony_ci size_t count, loff_t *ppos) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 74562306a36Sopenharmony_ci char buf[3]; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ? 'Y' : 'N'; 74862306a36Sopenharmony_ci buf[1] = '\n'; 74962306a36Sopenharmony_ci buf[2] = '\0'; 75062306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic ssize_t force_static_address_write(struct file *file, 75462306a36Sopenharmony_ci const char __user *user_buf, 75562306a36Sopenharmony_ci size_t count, loff_t *ppos) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 75862306a36Sopenharmony_ci bool enable; 75962306a36Sopenharmony_ci int err; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (hdev_is_powered(hdev)) 76262306a36Sopenharmony_ci return -EBUSY; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci err = kstrtobool_from_user(user_buf, count, &enable); 76562306a36Sopenharmony_ci if (err) 76662306a36Sopenharmony_ci return err; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (enable == hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR)) 76962306a36Sopenharmony_ci return -EALREADY; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci hci_dev_change_flag(hdev, HCI_FORCE_STATIC_ADDR); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return count; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic const struct file_operations force_static_address_fops = { 77762306a36Sopenharmony_ci .open = simple_open, 77862306a36Sopenharmony_ci .read = force_static_address_read, 77962306a36Sopenharmony_ci .write = force_static_address_write, 78062306a36Sopenharmony_ci .llseek = default_llseek, 78162306a36Sopenharmony_ci}; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int white_list_show(struct seq_file *f, void *ptr) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 78662306a36Sopenharmony_ci struct bdaddr_list *b; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci hci_dev_lock(hdev); 78962306a36Sopenharmony_ci list_for_each_entry(b, &hdev->le_accept_list, list) 79062306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); 79162306a36Sopenharmony_ci hci_dev_unlock(hdev); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return 0; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(white_list); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int resolv_list_show(struct seq_file *f, void *ptr) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 80162306a36Sopenharmony_ci struct bdaddr_list *b; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci hci_dev_lock(hdev); 80462306a36Sopenharmony_ci list_for_each_entry(b, &hdev->le_resolv_list, list) 80562306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); 80662306a36Sopenharmony_ci hci_dev_unlock(hdev); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(resolv_list); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic int identity_resolving_keys_show(struct seq_file *f, void *ptr) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 81662306a36Sopenharmony_ci struct smp_irk *irk; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci rcu_read_lock(); 81962306a36Sopenharmony_ci list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) { 82062306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u) %*phN %pMR\n", 82162306a36Sopenharmony_ci &irk->bdaddr, irk->addr_type, 82262306a36Sopenharmony_ci 16, irk->val, &irk->rpa); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci rcu_read_unlock(); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(identity_resolving_keys); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int long_term_keys_show(struct seq_file *f, void *ptr) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct hci_dev *hdev = f->private; 83462306a36Sopenharmony_ci struct smp_ltk *ltk; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci rcu_read_lock(); 83762306a36Sopenharmony_ci list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list) 83862306a36Sopenharmony_ci seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n", 83962306a36Sopenharmony_ci <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, 84062306a36Sopenharmony_ci ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), 84162306a36Sopenharmony_ci __le64_to_cpu(ltk->rand), 16, ltk->val); 84262306a36Sopenharmony_ci rcu_read_unlock(); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(long_term_keys); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int conn_min_interval_set(void *data, u64 val) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct hci_dev *hdev = data; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) 85462306a36Sopenharmony_ci return -EINVAL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci hci_dev_lock(hdev); 85762306a36Sopenharmony_ci hdev->le_conn_min_interval = val; 85862306a36Sopenharmony_ci hci_dev_unlock(hdev); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic int conn_min_interval_get(void *data, u64 *val) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct hci_dev *hdev = data; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci hci_dev_lock(hdev); 86862306a36Sopenharmony_ci *val = hdev->le_conn_min_interval; 86962306a36Sopenharmony_ci hci_dev_unlock(hdev); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return 0; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(conn_min_interval_fops, conn_min_interval_get, 87562306a36Sopenharmony_ci conn_min_interval_set, "%llu\n"); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int conn_max_interval_set(void *data, u64 val) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct hci_dev *hdev = data; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) 88262306a36Sopenharmony_ci return -EINVAL; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci hci_dev_lock(hdev); 88562306a36Sopenharmony_ci hdev->le_conn_max_interval = val; 88662306a36Sopenharmony_ci hci_dev_unlock(hdev); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return 0; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int conn_max_interval_get(void *data, u64 *val) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct hci_dev *hdev = data; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci hci_dev_lock(hdev); 89662306a36Sopenharmony_ci *val = hdev->le_conn_max_interval; 89762306a36Sopenharmony_ci hci_dev_unlock(hdev); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci return 0; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, 90362306a36Sopenharmony_ci conn_max_interval_set, "%llu\n"); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic int conn_latency_set(void *data, u64 val) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct hci_dev *hdev = data; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (val > 0x01f3) 91062306a36Sopenharmony_ci return -EINVAL; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci hci_dev_lock(hdev); 91362306a36Sopenharmony_ci hdev->le_conn_latency = val; 91462306a36Sopenharmony_ci hci_dev_unlock(hdev); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int conn_latency_get(void *data, u64 *val) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct hci_dev *hdev = data; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci hci_dev_lock(hdev); 92462306a36Sopenharmony_ci *val = hdev->le_conn_latency; 92562306a36Sopenharmony_ci hci_dev_unlock(hdev); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(conn_latency_fops, conn_latency_get, 93162306a36Sopenharmony_ci conn_latency_set, "%llu\n"); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic int supervision_timeout_set(void *data, u64 val) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct hci_dev *hdev = data; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (val < 0x000a || val > 0x0c80) 93862306a36Sopenharmony_ci return -EINVAL; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci hci_dev_lock(hdev); 94162306a36Sopenharmony_ci hdev->le_supv_timeout = val; 94262306a36Sopenharmony_ci hci_dev_unlock(hdev); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci return 0; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int supervision_timeout_get(void *data, u64 *val) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct hci_dev *hdev = data; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci hci_dev_lock(hdev); 95262306a36Sopenharmony_ci *val = hdev->le_supv_timeout; 95362306a36Sopenharmony_ci hci_dev_unlock(hdev); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, 95962306a36Sopenharmony_ci supervision_timeout_set, "%llu\n"); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int adv_channel_map_set(void *data, u64 val) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct hci_dev *hdev = data; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (val < 0x01 || val > 0x07) 96662306a36Sopenharmony_ci return -EINVAL; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci hci_dev_lock(hdev); 96962306a36Sopenharmony_ci hdev->le_adv_channel_map = val; 97062306a36Sopenharmony_ci hci_dev_unlock(hdev); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic int adv_channel_map_get(void *data, u64 *val) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct hci_dev *hdev = data; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci hci_dev_lock(hdev); 98062306a36Sopenharmony_ci *val = hdev->le_adv_channel_map; 98162306a36Sopenharmony_ci hci_dev_unlock(hdev); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci return 0; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, 98762306a36Sopenharmony_ci adv_channel_map_set, "%llu\n"); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic int adv_min_interval_set(void *data, u64 val) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct hci_dev *hdev = data; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) 99462306a36Sopenharmony_ci return -EINVAL; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci hci_dev_lock(hdev); 99762306a36Sopenharmony_ci hdev->le_adv_min_interval = val; 99862306a36Sopenharmony_ci hci_dev_unlock(hdev); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int adv_min_interval_get(void *data, u64 *val) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct hci_dev *hdev = data; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci hci_dev_lock(hdev); 100862306a36Sopenharmony_ci *val = hdev->le_adv_min_interval; 100962306a36Sopenharmony_ci hci_dev_unlock(hdev); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, 101562306a36Sopenharmony_ci adv_min_interval_set, "%llu\n"); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int adv_max_interval_set(void *data, u64 val) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct hci_dev *hdev = data; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) 102262306a36Sopenharmony_ci return -EINVAL; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci hci_dev_lock(hdev); 102562306a36Sopenharmony_ci hdev->le_adv_max_interval = val; 102662306a36Sopenharmony_ci hci_dev_unlock(hdev); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int adv_max_interval_get(void *data, u64 *val) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct hci_dev *hdev = data; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci hci_dev_lock(hdev); 103662306a36Sopenharmony_ci *val = hdev->le_adv_max_interval; 103762306a36Sopenharmony_ci hci_dev_unlock(hdev); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, 104362306a36Sopenharmony_ci adv_max_interval_set, "%llu\n"); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic int min_key_size_set(void *data, u64 val) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct hci_dev *hdev = data; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci hci_dev_lock(hdev); 105062306a36Sopenharmony_ci if (val > hdev->le_max_key_size || val < SMP_MIN_ENC_KEY_SIZE) { 105162306a36Sopenharmony_ci hci_dev_unlock(hdev); 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci hdev->le_min_key_size = val; 105662306a36Sopenharmony_ci hci_dev_unlock(hdev); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int min_key_size_get(void *data, u64 *val) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct hci_dev *hdev = data; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci hci_dev_lock(hdev); 106662306a36Sopenharmony_ci *val = hdev->le_min_key_size; 106762306a36Sopenharmony_ci hci_dev_unlock(hdev); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return 0; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(min_key_size_fops, min_key_size_get, 107362306a36Sopenharmony_ci min_key_size_set, "%llu\n"); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic int max_key_size_set(void *data, u64 val) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct hci_dev *hdev = data; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci hci_dev_lock(hdev); 108062306a36Sopenharmony_ci if (val > SMP_MAX_ENC_KEY_SIZE || val < hdev->le_min_key_size) { 108162306a36Sopenharmony_ci hci_dev_unlock(hdev); 108262306a36Sopenharmony_ci return -EINVAL; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci hdev->le_max_key_size = val; 108662306a36Sopenharmony_ci hci_dev_unlock(hdev); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci return 0; 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int max_key_size_get(void *data, u64 *val) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci struct hci_dev *hdev = data; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci hci_dev_lock(hdev); 109662306a36Sopenharmony_ci *val = hdev->le_max_key_size; 109762306a36Sopenharmony_ci hci_dev_unlock(hdev); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(max_key_size_fops, max_key_size_get, 110362306a36Sopenharmony_ci max_key_size_set, "%llu\n"); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int auth_payload_timeout_set(void *data, u64 val) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct hci_dev *hdev = data; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (val < 0x0001 || val > 0xffff) 111062306a36Sopenharmony_ci return -EINVAL; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci hci_dev_lock(hdev); 111362306a36Sopenharmony_ci hdev->auth_payload_timeout = val; 111462306a36Sopenharmony_ci hci_dev_unlock(hdev); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic int auth_payload_timeout_get(void *data, u64 *val) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct hci_dev *hdev = data; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci hci_dev_lock(hdev); 112462306a36Sopenharmony_ci *val = hdev->auth_payload_timeout; 112562306a36Sopenharmony_ci hci_dev_unlock(hdev); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return 0; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(auth_payload_timeout_fops, 113162306a36Sopenharmony_ci auth_payload_timeout_get, 113262306a36Sopenharmony_ci auth_payload_timeout_set, "%llu\n"); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic ssize_t force_no_mitm_read(struct file *file, 113562306a36Sopenharmony_ci char __user *user_buf, 113662306a36Sopenharmony_ci size_t count, loff_t *ppos) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 113962306a36Sopenharmony_ci char buf[3]; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM) ? 'Y' : 'N'; 114262306a36Sopenharmony_ci buf[1] = '\n'; 114362306a36Sopenharmony_ci buf[2] = '\0'; 114462306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic ssize_t force_no_mitm_write(struct file *file, 114862306a36Sopenharmony_ci const char __user *user_buf, 114962306a36Sopenharmony_ci size_t count, loff_t *ppos) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 115262306a36Sopenharmony_ci char buf[32]; 115362306a36Sopenharmony_ci size_t buf_size = min(count, (sizeof(buf) - 1)); 115462306a36Sopenharmony_ci bool enable; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (copy_from_user(buf, user_buf, buf_size)) 115762306a36Sopenharmony_ci return -EFAULT; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci buf[buf_size] = '\0'; 116062306a36Sopenharmony_ci if (kstrtobool(buf, &enable)) 116162306a36Sopenharmony_ci return -EINVAL; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (enable == hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM)) 116462306a36Sopenharmony_ci return -EALREADY; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci hci_dev_change_flag(hdev, HCI_FORCE_NO_MITM); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return count; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic const struct file_operations force_no_mitm_fops = { 117262306a36Sopenharmony_ci .open = simple_open, 117362306a36Sopenharmony_ci .read = force_no_mitm_read, 117462306a36Sopenharmony_ci .write = force_no_mitm_write, 117562306a36Sopenharmony_ci .llseek = default_llseek, 117662306a36Sopenharmony_ci}; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ciDEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter, 117962306a36Sopenharmony_ci HCI_QUIRK_STRICT_DUPLICATE_FILTER); 118062306a36Sopenharmony_ciDEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery, 118162306a36Sopenharmony_ci HCI_QUIRK_SIMULTANEOUS_DISCOVERY); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_civoid hci_debugfs_create_le(struct hci_dev *hdev) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci debugfs_create_file("identity", 0400, hdev->debugfs, hdev, 118662306a36Sopenharmony_ci &identity_fops); 118762306a36Sopenharmony_ci debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, hdev, 118862306a36Sopenharmony_ci &rpa_timeout_fops); 118962306a36Sopenharmony_ci debugfs_create_file("random_address", 0444, hdev->debugfs, hdev, 119062306a36Sopenharmony_ci &random_address_fops); 119162306a36Sopenharmony_ci debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, 119262306a36Sopenharmony_ci &static_address_fops); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* For controllers with a public address, provide a debug 119562306a36Sopenharmony_ci * option to force the usage of the configured static 119662306a36Sopenharmony_ci * address. By default the public address is used. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci if (bacmp(&hdev->bdaddr, BDADDR_ANY)) 119962306a36Sopenharmony_ci debugfs_create_file("force_static_address", 0644, 120062306a36Sopenharmony_ci hdev->debugfs, hdev, 120162306a36Sopenharmony_ci &force_static_address_fops); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci debugfs_create_u8("white_list_size", 0444, hdev->debugfs, 120462306a36Sopenharmony_ci &hdev->le_accept_list_size); 120562306a36Sopenharmony_ci debugfs_create_file("white_list", 0444, hdev->debugfs, hdev, 120662306a36Sopenharmony_ci &white_list_fops); 120762306a36Sopenharmony_ci debugfs_create_u8("resolv_list_size", 0444, hdev->debugfs, 120862306a36Sopenharmony_ci &hdev->le_resolv_list_size); 120962306a36Sopenharmony_ci debugfs_create_file("resolv_list", 0444, hdev->debugfs, hdev, 121062306a36Sopenharmony_ci &resolv_list_fops); 121162306a36Sopenharmony_ci debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs, 121262306a36Sopenharmony_ci hdev, &identity_resolving_keys_fops); 121362306a36Sopenharmony_ci debugfs_create_file("long_term_keys", 0400, hdev->debugfs, hdev, 121462306a36Sopenharmony_ci &long_term_keys_fops); 121562306a36Sopenharmony_ci debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, hdev, 121662306a36Sopenharmony_ci &conn_min_interval_fops); 121762306a36Sopenharmony_ci debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, 121862306a36Sopenharmony_ci &conn_max_interval_fops); 121962306a36Sopenharmony_ci debugfs_create_file("conn_latency", 0644, hdev->debugfs, hdev, 122062306a36Sopenharmony_ci &conn_latency_fops); 122162306a36Sopenharmony_ci debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, hdev, 122262306a36Sopenharmony_ci &supervision_timeout_fops); 122362306a36Sopenharmony_ci debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, 122462306a36Sopenharmony_ci &adv_channel_map_fops); 122562306a36Sopenharmony_ci debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, hdev, 122662306a36Sopenharmony_ci &adv_min_interval_fops); 122762306a36Sopenharmony_ci debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, hdev, 122862306a36Sopenharmony_ci &adv_max_interval_fops); 122962306a36Sopenharmony_ci debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, 123062306a36Sopenharmony_ci &hdev->discov_interleaved_timeout); 123162306a36Sopenharmony_ci debugfs_create_file("min_key_size", 0644, hdev->debugfs, hdev, 123262306a36Sopenharmony_ci &min_key_size_fops); 123362306a36Sopenharmony_ci debugfs_create_file("max_key_size", 0644, hdev->debugfs, hdev, 123462306a36Sopenharmony_ci &max_key_size_fops); 123562306a36Sopenharmony_ci debugfs_create_file("auth_payload_timeout", 0644, hdev->debugfs, hdev, 123662306a36Sopenharmony_ci &auth_payload_timeout_fops); 123762306a36Sopenharmony_ci debugfs_create_file("force_no_mitm", 0644, hdev->debugfs, hdev, 123862306a36Sopenharmony_ci &force_no_mitm_fops); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci debugfs_create_file("quirk_strict_duplicate_filter", 0644, 124162306a36Sopenharmony_ci hdev->debugfs, hdev, 124262306a36Sopenharmony_ci &quirk_strict_duplicate_filter_fops); 124362306a36Sopenharmony_ci debugfs_create_file("quirk_simultaneous_discovery", 0644, 124462306a36Sopenharmony_ci hdev->debugfs, hdev, 124562306a36Sopenharmony_ci &quirk_simultaneous_discovery_fops); 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_civoid hci_debugfs_create_conn(struct hci_conn *conn) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct hci_dev *hdev = conn->hdev; 125162306a36Sopenharmony_ci char name[6]; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(hdev->debugfs) || conn->debugfs) 125462306a36Sopenharmony_ci return; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci snprintf(name, sizeof(name), "%u", conn->handle); 125762306a36Sopenharmony_ci conn->debugfs = debugfs_create_dir(name, hdev->debugfs); 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic ssize_t dut_mode_read(struct file *file, char __user *user_buf, 126162306a36Sopenharmony_ci size_t count, loff_t *ppos) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 126462306a36Sopenharmony_ci char buf[3]; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N'; 126762306a36Sopenharmony_ci buf[1] = '\n'; 126862306a36Sopenharmony_ci buf[2] = '\0'; 126962306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic ssize_t dut_mode_write(struct file *file, const char __user *user_buf, 127362306a36Sopenharmony_ci size_t count, loff_t *ppos) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 127662306a36Sopenharmony_ci struct sk_buff *skb; 127762306a36Sopenharmony_ci bool enable; 127862306a36Sopenharmony_ci int err; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (!test_bit(HCI_UP, &hdev->flags)) 128162306a36Sopenharmony_ci return -ENETDOWN; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci err = kstrtobool_from_user(user_buf, count, &enable); 128462306a36Sopenharmony_ci if (err) 128562306a36Sopenharmony_ci return err; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE)) 128862306a36Sopenharmony_ci return -EALREADY; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci hci_req_sync_lock(hdev); 129162306a36Sopenharmony_ci if (enable) 129262306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL, 129362306a36Sopenharmony_ci HCI_CMD_TIMEOUT); 129462306a36Sopenharmony_ci else 129562306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, 129662306a36Sopenharmony_ci HCI_CMD_TIMEOUT); 129762306a36Sopenharmony_ci hci_req_sync_unlock(hdev); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (IS_ERR(skb)) 130062306a36Sopenharmony_ci return PTR_ERR(skb); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci kfree_skb(skb); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci hci_dev_change_flag(hdev, HCI_DUT_MODE); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return count; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic const struct file_operations dut_mode_fops = { 131062306a36Sopenharmony_ci .open = simple_open, 131162306a36Sopenharmony_ci .read = dut_mode_read, 131262306a36Sopenharmony_ci .write = dut_mode_write, 131362306a36Sopenharmony_ci .llseek = default_llseek, 131462306a36Sopenharmony_ci}; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic ssize_t vendor_diag_read(struct file *file, char __user *user_buf, 131762306a36Sopenharmony_ci size_t count, loff_t *ppos) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 132062306a36Sopenharmony_ci char buf[3]; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N'; 132362306a36Sopenharmony_ci buf[1] = '\n'; 132462306a36Sopenharmony_ci buf[2] = '\0'; 132562306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic ssize_t vendor_diag_write(struct file *file, const char __user *user_buf, 132962306a36Sopenharmony_ci size_t count, loff_t *ppos) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct hci_dev *hdev = file->private_data; 133262306a36Sopenharmony_ci bool enable; 133362306a36Sopenharmony_ci int err; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci err = kstrtobool_from_user(user_buf, count, &enable); 133662306a36Sopenharmony_ci if (err) 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci /* When the diagnostic flags are not persistent and the transport 134062306a36Sopenharmony_ci * is not active or in user channel operation, then there is no need 134162306a36Sopenharmony_ci * for the vendor callback. Instead just store the desired value and 134262306a36Sopenharmony_ci * the setting will be programmed when the controller gets powered on. 134362306a36Sopenharmony_ci */ 134462306a36Sopenharmony_ci if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) && 134562306a36Sopenharmony_ci (!test_bit(HCI_RUNNING, &hdev->flags) || 134662306a36Sopenharmony_ci hci_dev_test_flag(hdev, HCI_USER_CHANNEL))) 134762306a36Sopenharmony_ci goto done; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci hci_req_sync_lock(hdev); 135062306a36Sopenharmony_ci err = hdev->set_diag(hdev, enable); 135162306a36Sopenharmony_ci hci_req_sync_unlock(hdev); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (err < 0) 135462306a36Sopenharmony_ci return err; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cidone: 135762306a36Sopenharmony_ci if (enable) 135862306a36Sopenharmony_ci hci_dev_set_flag(hdev, HCI_VENDOR_DIAG); 135962306a36Sopenharmony_ci else 136062306a36Sopenharmony_ci hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return count; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic const struct file_operations vendor_diag_fops = { 136662306a36Sopenharmony_ci .open = simple_open, 136762306a36Sopenharmony_ci .read = vendor_diag_read, 136862306a36Sopenharmony_ci .write = vendor_diag_write, 136962306a36Sopenharmony_ci .llseek = default_llseek, 137062306a36Sopenharmony_ci}; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_civoid hci_debugfs_create_basic(struct hci_dev *hdev) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev, 137562306a36Sopenharmony_ci &dut_mode_fops); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (hdev->set_diag) 137862306a36Sopenharmony_ci debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev, 137962306a36Sopenharmony_ci &vendor_diag_fops); 138062306a36Sopenharmony_ci} 1381