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			   &ltk->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