#include <linux/export.h>
#include <linux/idr.h>
-
#include <linux/rfkill.h>
+#include <linux/debugfs.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
hci_sock_dev_event(hdev, event);
}
+/* ---- HCI debugfs entries ---- */
+
+static int inquiry_cache_show(struct seq_file *f, void *p)
+{
+ struct hci_dev *hdev = f->private;
+ struct discovery_state *cache = &hdev->discovery;
+ struct inquiry_entry *e;
+
+ hci_dev_lock(hdev);
+
+ list_for_each_entry(e, &cache->all, all) {
+ struct inquiry_data *data = &e->data;
+ seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+ &data->bdaddr,
+ data->pscan_rep_mode, data->pscan_period_mode,
+ data->pscan_mode, data->dev_class[2],
+ data->dev_class[1], data->dev_class[0],
+ __le16_to_cpu(data->clock_offset),
+ data->rssi, data->ssp_mode, e->timestamp);
+ }
+
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int inquiry_cache_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, inquiry_cache_show, inode->i_private);
+}
+
+static const struct file_operations inquiry_cache_fops = {
+ .open = inquiry_cache_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
static void bredr_setup(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
+
__le16 param;
__u8 flt_type;
/* Read Voice Setting */
hci_req_add(req, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+ /* Read Number of Supported IAC */
+ hci_req_add(req, HCI_OP_READ_NUM_SUPPORTED_IAC, 0, NULL);
+
+ /* Read Current IAC LAP */
+ hci_req_add(req, HCI_OP_READ_CURRENT_IAC_LAP, 0, NULL);
+
/* Clear Event Filters */
flt_type = HCI_FLT_CLEAR_ALL;
hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
param = __constant_cpu_to_le16(0x7d00);
hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
- /* Read page scan parameters */
- if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) {
+ /* AVM Berlin (31), aka "BlueFRITZ!", reports version 1.2,
+ * but it does not support page scan related HCI commands.
+ */
+ if (hdev->manufacturer != 31 && hdev->hci_ver > BLUETOOTH_VER_1_1) {
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
}
if (hdev->commands[5] & 0x10)
hci_setup_link_policy(req);
- if (lmp_le_capable(hdev)) {
+ if (lmp_le_capable(hdev))
hci_set_le_support(req);
- hci_update_ad(req);
- }
/* Read features beyond page 1 if available */
for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
if (err < 0)
return err;
- return __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
+ err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ /* Only create debugfs entries during the initial setup
+ * phase and not every time the controller gets powered on.
+ */
+ if (!test_bit(HCI_SETUP, &hdev->dev_flags))
+ return 0;
+
+ if (lmp_bredr_capable(hdev)) {
+ debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
+ hdev, &inquiry_cache_fops);
+ }
+
+ return 0;
}
static void hci_scan_req(struct hci_request *req, unsigned long opt)
return err;
}
-static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
-{
- u8 ad_len = 0, flags = 0;
- size_t name_len;
-
- if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
- flags |= LE_AD_GENERAL;
-
- if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
- if (lmp_le_br_capable(hdev))
- flags |= LE_AD_SIM_LE_BREDR_CTRL;
- if (lmp_host_le_br_capable(hdev))
- flags |= LE_AD_SIM_LE_BREDR_HOST;
- } else {
- flags |= LE_AD_NO_BREDR;
- }
-
- if (flags) {
- BT_DBG("adv flags 0x%02x", flags);
-
- ptr[0] = 2;
- ptr[1] = EIR_FLAGS;
- ptr[2] = flags;
-
- ad_len += 3;
- ptr += 3;
- }
-
- if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
- ptr[0] = 2;
- ptr[1] = EIR_TX_POWER;
- ptr[2] = (u8) hdev->adv_tx_power;
-
- ad_len += 3;
- ptr += 3;
- }
-
- name_len = strlen(hdev->dev_name);
- if (name_len > 0) {
- size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
-
- if (name_len > max_len) {
- name_len = max_len;
- ptr[1] = EIR_NAME_SHORT;
- } else
- ptr[1] = EIR_NAME_COMPLETE;
-
- ptr[0] = name_len + 1;
-
- memcpy(ptr + 2, hdev->dev_name, name_len);
-
- ad_len += (name_len + 2);
- ptr += (name_len + 2);
- }
-
- return ad_len;
-}
-
-void hci_update_ad(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- struct hci_cp_le_set_adv_data cp;
- u8 len;
-
- if (!lmp_le_capable(hdev))
- return;
-
- memset(&cp, 0, sizeof(cp));
-
- len = create_ad(hdev, cp.data);
-
- if (hdev->adv_data_len == len &&
- memcmp(cp.data, hdev->adv_data, len) == 0)
- return;
-
- memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
- hdev->adv_data_len = len;
-
- cp.length = len;
-
- hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
-}
-
static int hci_dev_do_open(struct hci_dev *hdev)
{
int ret = 0;
cancel_delayed_work(&hdev->discov_off);
hdev->discov_timeout = 0;
clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
+ clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
}
if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
skb_queue_purge(&hdev->cmd_q);
atomic_set(&hdev->cmd_cnt, 1);
if (!test_bit(HCI_RAW, &hdev->flags) &&
+ !test_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags);
__hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
static void hci_discov_off(struct work_struct *work)
{
struct hci_dev *hdev;
- u8 scan = SCAN_PAGE;
hdev = container_of(work, struct hci_dev, discov_off.work);
BT_DBG("%s", hdev->name);
- hci_dev_lock(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
-
- hdev->discov_timeout = 0;
-
- hci_dev_unlock(hdev);
+ mgmt_discoverable_timeout(hdev);
}
int hci_uuids_clear(struct hci_dev *hdev)
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
- hdev->io_capability = 0x03; /* No Input No Output */
+ hdev->num_iac = 0x01; /* One IAC support is mandatory */
+ hdev->io_capability = 0x03; /* No Input No Output */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
}
}
}
-
-u8 bdaddr_to_le(u8 bdaddr_type)
-{
- switch (bdaddr_type) {
- case BDADDR_LE_PUBLIC:
- return ADDR_LE_DEV_PUBLIC;
-
- default:
- /* Fallback to LE Random address type */
- return ADDR_LE_DEV_RANDOM;
- }
-}