Release 4.11 net/bluetooth/hci_core.c
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2011 ProFUSION Embedded Systems
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/* Bluetooth HCI core. */
#include <linux/export.h>
#include <linux/idr.h>
#include <linux/rfkill.h>
#include <linux/debugfs.h>
#include <linux/crypto.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/mgmt.h>
#include "hci_request.h"
#include "hci_debugfs.h"
#include "smp.h"
#include "leds.h"
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work);
/* HCI device list */
LIST_HEAD(hci_dev_list);
DEFINE_RWLOCK(hci_dev_list_lock);
/* HCI callback list */
LIST_HEAD(hci_cb_list);
DEFINE_MUTEX(hci_cb_list_lock);
/* HCI ID Numbering */
static DEFINE_IDA(hci_index_ida);
/* ---- HCI debugfs entries ---- */
static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 82 | 100.00% | 2 | 100.00% |
Total | 82 | 100.00% | 2 | 100.00% |
static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
struct sk_buff *skb;
char buf[32];
size_t buf_size = min(count, (sizeof(buf)-1));
bool enable;
if (!test_bit(HCI_UP, &hdev->flags))
return -ENETDOWN;
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (strtobool(buf, &enable))
return -EINVAL;
if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE))
return -EALREADY;
hci_req_sync_lock(hdev);
if (enable)
skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL,
HCI_CMD_TIMEOUT);
else
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
HCI_CMD_TIMEOUT);
hci_req_sync_unlock(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
hci_dev_change_flag(hdev, HCI_DUT_MODE);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 203 | 99.02% | 2 | 66.67% |
Johan Hedberg | 2 | 0.98% | 1 | 33.33% |
Total | 205 | 100.00% | 3 | 100.00% |
static const struct file_operations dut_mode_fops = {
.open = simple_open,
.read = dut_mode_read,
.write = dut_mode_write,
.llseek = default_llseek,
};
static ssize_t vendor_diag_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 82 | 100.00% | 1 | 100.00% |
Total | 82 | 100.00% | 1 | 100.00% |
static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[32];
size_t buf_size = min(count, (sizeof(buf)-1));
bool enable;
int err;
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (strtobool(buf, &enable))
return -EINVAL;
/* When the diagnostic flags are not persistent and the transport
* is not active, then there is no need for the vendor callback.
*
* Instead just store the desired value. If needed the setting
* will be programmed when the controller gets powered on.
*/
if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
!test_bit(HCI_RUNNING, &hdev->flags))
goto done;
hci_req_sync_lock(hdev);
err = hdev->set_diag(hdev, enable);
hci_req_sync_unlock(hdev);
if (err < 0)
return err;
done:
if (enable)
hci_dev_set_flag(hdev, HCI_VENDOR_DIAG);
else
hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 177 | 98.88% | 2 | 66.67% |
Johan Hedberg | 2 | 1.12% | 1 | 33.33% |
Total | 179 | 100.00% | 3 | 100.00% |
static const struct file_operations vendor_diag_fops = {
.open = simple_open,
.read = vendor_diag_read,
.write = vendor_diag_write,
.llseek = default_llseek,
};
static void hci_debugfs_create_basic(struct hci_dev *hdev)
{
debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
&dut_mode_fops);
if (hdev->set_diag)
debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev,
&vendor_diag_fops);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 49 | 100.00% | 1 | 100.00% |
Total | 49 | 100.00% | 1 | 100.00% |
static int hci_reset_req(struct hci_request *req, unsigned long opt)
{
BT_DBG("%s %ld", req->hdev->name, opt);
/* Reset device */
set_bit(HCI_RESET, &req->hdev->flags);
hci_req_add(req, HCI_OP_RESET, 0, NULL);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 18 | 32.73% | 2 | 28.57% |
Maksim Krasnyanskiy | 14 | 25.45% | 1 | 14.29% |
Johan Hedberg | 12 | 21.82% | 2 | 28.57% |
Gustavo Fernando Padovan | 10 | 18.18% | 1 | 14.29% |
Marcel Holtmann | 1 | 1.82% | 1 | 14.29% |
Total | 55 | 100.00% | 7 | 100.00% |
static void bredr_init(struct hci_request *req)
{
req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
/* Read Local Supported Features */
hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
/* Read Local Version */
hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read BD Address */
hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 20 | 36.36% | 2 | 25.00% |
Marcel Holtmann | 11 | 20.00% | 2 | 25.00% |
Linus Torvalds | 9 | 16.36% | 1 | 12.50% |
Maksim Krasnyanskiy | 8 | 14.55% | 1 | 12.50% |
Andrei Emeltchenko | 7 | 12.73% | 2 | 25.00% |
Total | 55 | 100.00% | 8 | 100.00% |
static void amp_init1(struct hci_request *req)
{
req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
/* Read Local Version */
hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read Local Supported Commands */
hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
/* Read Local AMP Info */
hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
/* Read Data Blk size */
hci_req_add(req, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
/* Read Flow Control Mode */
hci_req_add(req, HCI_OP_READ_FLOW_CONTROL_MODE, 0, NULL);
/* Read Location Data */
hci_req_add(req, HCI_OP_READ_LOCATION_DATA, 0, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 44 | 48.35% | 3 | 42.86% |
Marcel Holtmann | 32 | 35.16% | 2 | 28.57% |
Andrei Emeltchenko | 15 | 16.48% | 2 | 28.57% |
Total | 91 | 100.00% | 7 | 100.00% |
static int amp_init2(struct hci_request *req)
{
/* Read Local Supported Features. Not all AMP controllers
* support this so it's placed conditionally in the second
* stage init.
*/
if (req->hdev->commands[14] & 0x20)
hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 29 | 74.36% | 3 | 75.00% |
Marcel Holtmann | 10 | 25.64% | 1 | 25.00% |
Total | 39 | 100.00% | 4 | 100.00% |
static int hci_init1_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
BT_DBG("%s %ld", hdev->name, opt);
/* Reset */
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
hci_reset_req(req, 0);
switch (hdev->dev_type) {
case HCI_PRIMARY:
bredr_init(req);
break;
case HCI_AMP:
amp_init1(req);
break;
default:
BT_ERR("Unknown device type %d", hdev->dev_type);
break;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 95 | 98.96% | 4 | 80.00% |
Marcel Holtmann | 1 | 1.04% | 1 | 20.00% |
Total | 96 | 100.00% | 5 | 100.00% |
static void bredr_setup(struct hci_request *req)
{
__le16 param;
__u8 flt_type;
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_req_add(req, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
/* Read Class of Device */
hci_req_add(req, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
/* Read Local Name */
hci_req_add(req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
/* 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);
/* Connection accept timeout ~20 secs */
param = cpu_to_le16(0x7d00);
hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 101 | 80.16% | 2 | 40.00% |
Marcel Holtmann | 24 | 19.05% | 2 | 40.00% |
Joe Perches | 1 | 0.79% | 1 | 20.00% |
Total | 126 | 100.00% | 5 | 100.00% |
static void le_setup(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
/* Read LE Buffer Size */
hci_req_add(req, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
/* Read LE Local Supported Features */
hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
/* Read LE Supported States */
hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
/* LE-only controllers have LE implicitly enabled */
if (!lmp_bredr_capable(hdev))
hci_dev_set_flag(hdev, HCI_LE_ENABLED);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 57 | 79.17% | 3 | 60.00% |
Marcel Holtmann | 15 | 20.83% | 2 | 40.00% |
Total | 72 | 100.00% | 5 | 100.00% |
static void hci_setup_event_mask(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
/* The second byte is 0xff instead of 0x9f (two reserved bits
* disabled) since a Broadcom 1.2 dongle doesn't respond to the
* command otherwise.
*/
u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
* any event mask for pre 1.2 devices.
*/
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
return;
if (lmp_bredr_capable(hdev)) {
events[4] |= 0x01; /* Flow Specification Complete */
} else {
/* Use a different default for LE-only devices */
memset(events, 0, sizeof(events));
events[1] |= 0x20; /* Command Complete */
events[1] |= 0x40; /* Command Status */
events[1] |= 0x80; /* Hardware Error */
/* If the controller supports the Disconnect command, enable
* the corresponding event. In addition enable packet flow
* control related events.
*/
if (hdev->commands[0] & 0x20) {
events[0] |= 0x10; /* Disconnection Complete */
events[2] |= 0x04; /* Number of Completed Packets */
events[3] |= 0x02; /* Data Buffer Overflow */
}
/* If the controller supports the Read Remote Version
* Information command, enable the corresponding event.
*/
if (hdev->commands[2] & 0x80)
events[1] |= 0x08; /* Read Remote Version Information
* Complete
*/
if (hdev->le_features[0] & HCI_LE_ENCRYPTION) {
events[0] |= 0x80; /* Encryption Change */
events[5] |= 0x80; /* Encryption Key Refresh Complete */
}
}
if (lmp_inq_rssi_capable(hdev) ||
test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
events[4] |= 0x02; /* Inquiry Result with RSSI */
if (lmp_ext_feat_capable(hdev))
events[4] |= 0x04; /* Read Remote Extended Features Complete */
if (lmp_esco_capable(hdev)) {
events[5] |= 0x08; /* Synchronous Connection Complete */
events[5] |= 0x10; /* Synchronous Connection Changed */
}
if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
if (lmp_pause_enc_capable(hdev))
events[5] |= 0x80; /* Encryption Key Refresh Complete */
if (lmp_ext_inq_capable(hdev))
events[5] |= 0x40; /* Extended Inquiry Result */
if (lmp_no_flush_capable(hdev))
events[7] |= 0x01; /* Enhanced Flush Complete */
if (lmp_lsto_capable(hdev))
events[6] |= 0x80; /* Link Supervision Timeout Changed */
if (lmp_ssp_capable(hdev)) {
events[6] |= 0x01; /* IO Capability Request */
events[6] |= 0x02; /* IO Capability Response */
events[6] |= 0x04; /* User Confirmation Request */
events[6] |= 0x08; /* User Passkey Request */
events[6] |= 0x10; /* Remote OOB Data Request */
events[6] |= 0x20; /* Simple Pairing Complete */
events[7] |= 0x04; /* User Passkey Notification */
events[7] |= 0x08; /* Keypress Notification */
events[7] |= 0x10; /* Remote Host Supported
* Features Notification
*/
}
if (lmp_le_capable(hdev))
events[7] |= 0x20; /* LE Meta-Event */
hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 272 | 60.58% | 2 | 28.57% |
Marcel Holtmann | 177 | 39.42% | 5 | 71.43% |
Total | 449 | 100.00% | 7 | 100.00% |
static int hci_init2_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
if (hdev->dev_type == HCI_AMP)
return amp_init2(req);
if (lmp_bredr_capable(hdev))
bredr_setup(req);
else
hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
if (lmp_le_capable(hdev))
le_setup(req);
/* All Bluetooth 1.2 and later controllers should support the
* HCI command for reading the local supported commands.
*
* Unfortunately some controllers indicate Bluetooth 1.2 support,
* but do not have support for this command. If that is the case,
* the driver can quirk the behavior and skip reading the local
* supported commands.
*/
if (hdev->hci_ver > BLUETOOTH_VER_1_1 &&
!test_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks))
hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
if (lmp_ssp_capable(hdev)) {
/* When SSP is available, then the host features page
* should also be available as well. However some
* controllers list the max_page as 0 as long as SSP
* has not been enabled. To achieve proper debugging
* output, force the minimum max_page to 1 at least.
*/
hdev->max_page = 0x01;
if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
u8 mode = 0x01;
hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
sizeof(mode), &mode);
} else {
struct hci_cp_write_eir cp;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp));
hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
}
if (lmp_inq_rssi_capable(hdev) ||
test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks)) {
u8 mode;
/* If Extended Inquiry Result events are supported, then
* they are clearly preferred over Inquiry Result with RSSI
* events.
*/
mode = lmp_ext_inq_capable(hdev) ? 0x02 : 0x01;
hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
}
if (lmp_inq_tx_pwr_capable(hdev))
hci_req_add(req, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
if (lmp_ext_feat_capable(hdev)) {
struct hci_cp_read_local_ext_features cp;
cp.page = 0x01;
hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
sizeof(cp), &cp);
}
if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
u8 enable = 1;
hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
&enable);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 268 | 80.97% | 5 | 45.45% |
Marcel Holtmann | 63 | 19.03% | 6 | 54.55% |
Total | 331 | 100.00% | 11 | 100.00% |
static void hci_setup_link_policy(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
if (lmp_rswitch_capable(hdev))
link_policy |= HCI_LP_RSWITCH;
if (lmp_hold_capable(hdev))
link_policy |= HCI_LP_HOLD;
if (lmp_sniff_capable(hdev))
link_policy |= HCI_LP_SNIFF;
if (lmp_park_capable(hdev))
link_policy |= HCI_LP_PARK;
cp.policy = cpu_to_le16(link_policy);
hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 84 | 86.60% | 2 | 40.00% |
Andrei Emeltchenko | 13 | 13.40% | 3 | 60.00% |
Total | 97 | 100.00% | 5 | 100.00% |
static void hci_set_le_support(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_le_host_supported cp;
/* LE-only devices do not support explicit enablement */
if (!lmp_bredr_capable(hdev))
return;
memset(&cp, 0, sizeof(cp));
if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
cp.le = 0x01;
cp.simul = 0x00;
}
if (cp.le != lmp_host_le_capable(hdev))
hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
&cp);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 59 | 61.46% | 3 | 50.00% |
Andrei Emeltchenko | 33 | 34.38% | 1 | 16.67% |
Marcel Holtmann | 4 | 4.17% | 2 | 33.33% |
Total | 96 | 100.00% | 6 | 100.00% |
static void hci_set_event_mask_page_2(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* If Connectionless Slave Broadcast master role is supported
* enable all necessary events for it.
*/
if (lmp_csb_master_capable(hdev)) {
events[1] |= 0x40; /* Triggered Clock Capture */
events[1] |= 0x80; /* Synchronization Train Complete */
events[2] |= 0x10; /* Slave Page Response Timeout */
events[2] |= 0x20; /* CSB Channel Map Change */
}
/* If Connectionless Slave Broadcast slave role is supported
* enable all necessary events for it.
*/
if (lmp_csb_slave_capable(hdev)) {
events[2] |= 0x01; /* Synchronization Train Received */
events[2] |= 0x02; /* CSB Receive */
events[2] |= 0x04; /* CSB Timeout */
events[2] |= 0x08; /* Truncated Page Complete */
}
/* Enable Authenticated Payload Timeout Expired event if supported */
if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING)
events[2] |= 0x80;
hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 136 | 81.93% | 1 | 25.00% |
Marcel Holtmann | 30 | 18.07% | 3 | 75.00% |
Total | 166 | 100.00% | 4 | 100.00% |
static int hci_init3_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
u8 p;
hci_setup_event_mask(req);
if (hdev->commands[6] & 0x20 &&
!test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
struct hci_cp_read_stored_link_key cp;
bacpy(&cp.bdaddr, BDADDR_ANY);
cp.read_all = 0x01;
hci_req_add(req, HCI_OP_READ_STORED_LINK_KEY, sizeof(cp), &cp);
}
if (hdev->commands[5] & 0x10)
hci_setup_link_policy(req);
if (hdev->commands[8] & 0x01)
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
/* Some older Broadcom based Bluetooth 1.2 controllers do not
* support the Read Page Scan Type command. Check support for
* this command in the bit mask of supported commands.
*/
if (hdev->commands[13] & 0x01)
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
if (lmp_le_capable(hdev)) {
u8 events[8];
memset(events, 0, sizeof(events));
if (hdev->le_features[0] & HCI_LE_ENCRYPTION)
events[0] |= 0x10; /* LE Long Term Key Request */
/* If controller supports the Connection Parameters Request
* Link Layer Procedure, enable the corresponding event.
*/
if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC)
events[0] |= 0x20; /* LE Remote Connection
* Parameter Request
*/
/* If the controller supports the Data Length Extension
* feature, enable the corresponding event.
*/
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT)
events[0] |= 0x40; /* LE Data Length Change */
/* If the controller supports Extended Scanner Filter
* Policies, enable the correspondig event.
*/
if (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)
events[1] |= 0x04; /* LE Direct Advertising
* Report
*/
/* If the controller supports the LE Set Scan Enable command,
* enable the corresponding advertising report event.
*/
if (hdev->commands[26] & 0x08)
events[0] |= 0x02; /* LE Advertising Report */
/* If the controller supports the LE Create Connection
* command, enable the corresponding event.
*/
if (hdev->commands[26] & 0x10)
events[0] |= 0x01; /* LE Connection Complete */
/* If the controller supports the LE Connection Update
* command, enable the corresponding event.
*/
if (hdev->commands[27] & 0x04)
events[0] |= 0x04; /* LE Connection Update
* Complete
*/
/* If the controller supports the LE Read Remote Used Features
* command, enable the corresponding event.
*/
if (hdev->commands[27] & 0x20)
events[0] |= 0x08; /* LE Read Remote Used
* Features Complete
*/
/* If the controller supports the LE Read Local P-256
* Public Key command, enable the corresponding event.
*/
if (hdev->commands[34] & 0x02)
events[0] |= 0x80; /* LE Read Local P-256
* Public Key Complete
*/
/* If the controller supports the LE Generate DHKey
* command, enable the corresponding event.
*/
if (hdev->commands[34] & 0x04)
events[1] |= 0x01; /* LE Generate DHKey Complete */
hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
events);
if (hdev->commands[25] & 0x40) {
/* Read LE Advertising Channel TX Power */
hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
}
if (hdev->commands[26] & 0x40) {
/* Read LE White List Size */
hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE,
0, NULL);
}
if (hdev->commands[26] & 0x80) {
/* Clear LE White List */
hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
}
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
/* Read LE Maximum Data Length */
hci_req_add(req, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL);
/* Read LE Suggested Default Data Length */
hci_req_add(req, HCI_OP_LE_READ_DEF_DATA_LEN, 0, NULL);
}
hci_set_le_support