Release 4.11 net/bluetooth/mgmt.c
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
Copyright (C) 2011-2012 Intel Corporation
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 Management interface */
#include <linux/module.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/mgmt.h>
#include "hci_request.h"
#include "smp.h"
#include "mgmt_util.h"
#define MGMT_VERSION 1
#define MGMT_REVISION 14
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
MGMT_OP_SET_POWERED,
MGMT_OP_SET_DISCOVERABLE,
MGMT_OP_SET_CONNECTABLE,
MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_OP_SET_BONDABLE,
MGMT_OP_SET_LINK_SECURITY,
MGMT_OP_SET_SSP,
MGMT_OP_SET_HS,
MGMT_OP_SET_LE,
MGMT_OP_SET_DEV_CLASS,
MGMT_OP_SET_LOCAL_NAME,
MGMT_OP_ADD_UUID,
MGMT_OP_REMOVE_UUID,
MGMT_OP_LOAD_LINK_KEYS,
MGMT_OP_LOAD_LONG_TERM_KEYS,
MGMT_OP_DISCONNECT,
MGMT_OP_GET_CONNECTIONS,
MGMT_OP_PIN_CODE_REPLY,
MGMT_OP_PIN_CODE_NEG_REPLY,
MGMT_OP_SET_IO_CAPABILITY,
MGMT_OP_PAIR_DEVICE,
MGMT_OP_CANCEL_PAIR_DEVICE,
MGMT_OP_UNPAIR_DEVICE,
MGMT_OP_USER_CONFIRM_REPLY,
MGMT_OP_USER_CONFIRM_NEG_REPLY,
MGMT_OP_USER_PASSKEY_REPLY,
MGMT_OP_USER_PASSKEY_NEG_REPLY,
MGMT_OP_READ_LOCAL_OOB_DATA,
MGMT_OP_ADD_REMOTE_OOB_DATA,
MGMT_OP_REMOVE_REMOTE_OOB_DATA,
MGMT_OP_START_DISCOVERY,
MGMT_OP_STOP_DISCOVERY,
MGMT_OP_CONFIRM_NAME,
MGMT_OP_BLOCK_DEVICE,
MGMT_OP_UNBLOCK_DEVICE,
MGMT_OP_SET_DEVICE_ID,
MGMT_OP_SET_ADVERTISING,
MGMT_OP_SET_BREDR,
MGMT_OP_SET_STATIC_ADDRESS,
MGMT_OP_SET_SCAN_PARAMS,
MGMT_OP_SET_SECURE_CONN,
MGMT_OP_SET_DEBUG_KEYS,
MGMT_OP_SET_PRIVACY,
MGMT_OP_LOAD_IRKS,
MGMT_OP_GET_CONN_INFO,
MGMT_OP_GET_CLOCK_INFO,
MGMT_OP_ADD_DEVICE,
MGMT_OP_REMOVE_DEVICE,
MGMT_OP_LOAD_CONN_PARAM,
MGMT_OP_READ_UNCONF_INDEX_LIST,
MGMT_OP_READ_CONFIG_INFO,
MGMT_OP_SET_EXTERNAL_CONFIG,
MGMT_OP_SET_PUBLIC_ADDRESS,
MGMT_OP_START_SERVICE_DISCOVERY,
MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
MGMT_OP_READ_EXT_INDEX_LIST,
MGMT_OP_READ_ADV_FEATURES,
MGMT_OP_ADD_ADVERTISING,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_OP_START_LIMITED_DISCOVERY,
MGMT_OP_READ_EXT_INFO,
MGMT_OP_SET_APPEARANCE,
};
static const u16 mgmt_events[] = {
MGMT_EV_CONTROLLER_ERROR,
MGMT_EV_INDEX_ADDED,
MGMT_EV_INDEX_REMOVED,
MGMT_EV_NEW_SETTINGS,
MGMT_EV_CLASS_OF_DEV_CHANGED,
MGMT_EV_LOCAL_NAME_CHANGED,
MGMT_EV_NEW_LINK_KEY,
MGMT_EV_NEW_LONG_TERM_KEY,
MGMT_EV_DEVICE_CONNECTED,
MGMT_EV_DEVICE_DISCONNECTED,
MGMT_EV_CONNECT_FAILED,
MGMT_EV_PIN_CODE_REQUEST,
MGMT_EV_USER_CONFIRM_REQUEST,
MGMT_EV_USER_PASSKEY_REQUEST,
MGMT_EV_AUTH_FAILED,
MGMT_EV_DEVICE_FOUND,
MGMT_EV_DISCOVERING,
MGMT_EV_DEVICE_BLOCKED,
MGMT_EV_DEVICE_UNBLOCKED,
MGMT_EV_DEVICE_UNPAIRED,
MGMT_EV_PASSKEY_NOTIFY,
MGMT_EV_NEW_IRK,
MGMT_EV_NEW_CSRK,
MGMT_EV_DEVICE_ADDED,
MGMT_EV_DEVICE_REMOVED,
MGMT_EV_NEW_CONN_PARAM,
MGMT_EV_UNCONF_INDEX_ADDED,
MGMT_EV_UNCONF_INDEX_REMOVED,
MGMT_EV_NEW_CONFIG_OPTIONS,
MGMT_EV_EXT_INDEX_ADDED,
MGMT_EV_EXT_INDEX_REMOVED,
MGMT_EV_LOCAL_OOB_DATA_UPDATED,
MGMT_EV_ADVERTISING_ADDED,
MGMT_EV_ADVERTISING_REMOVED,
MGMT_EV_EXT_INFO_CHANGED,
};
static const u16 mgmt_untrusted_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
MGMT_OP_READ_UNCONF_INDEX_LIST,
MGMT_OP_READ_CONFIG_INFO,
MGMT_OP_READ_EXT_INDEX_LIST,
MGMT_OP_READ_EXT_INFO,
};
static const u16 mgmt_untrusted_events[] = {
MGMT_EV_INDEX_ADDED,
MGMT_EV_INDEX_REMOVED,
MGMT_EV_NEW_SETTINGS,
MGMT_EV_CLASS_OF_DEV_CHANGED,
MGMT_EV_LOCAL_NAME_CHANGED,
MGMT_EV_UNCONF_INDEX_ADDED,
MGMT_EV_UNCONF_INDEX_REMOVED,
MGMT_EV_NEW_CONFIG_OPTIONS,
MGMT_EV_EXT_INDEX_ADDED,
MGMT_EV_EXT_INDEX_REMOVED,
MGMT_EV_EXT_INFO_CHANGED,
};
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00"
/* HCI to MGMT error code conversion table */
static u8 mgmt_status_table[] = {
MGMT_STATUS_SUCCESS,
MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
MGMT_STATUS_NOT_CONNECTED, /* No Connection */
MGMT_STATUS_FAILED, /* Hardware Failure */
MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
MGMT_STATUS_NO_RESOURCES, /* Memory Full */
MGMT_STATUS_TIMEOUT, /* Connection Timeout */
MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
MGMT_STATUS_BUSY, /* Command Disallowed */
MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
MGMT_STATUS_REJECTED, /* Rejected Security */
MGMT_STATUS_REJECTED, /* Rejected Personal */
MGMT_STATUS_TIMEOUT, /* Host Timeout */
MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
MGMT_STATUS_DISCONNECTED, /* OE Power Off */
MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
MGMT_STATUS_BUSY, /* Repeated Attempts */
MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
MGMT_STATUS_FAILED, /* Unknown LMP PDU */
MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
MGMT_STATUS_REJECTED, /* Air Mode Rejected */
MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
MGMT_STATUS_FAILED, /* Unspecified Error */
MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
MGMT_STATUS_FAILED, /* Role Change Not Allowed */
MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
MGMT_STATUS_FAILED, /* Unit Link Key Used */
MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
MGMT_STATUS_TIMEOUT, /* Instant Passed */
MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
MGMT_STATUS_FAILED, /* Transaction Collision */
MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
MGMT_STATUS_REJECTED, /* QoS Rejected */
MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
MGMT_STATUS_REJECTED, /* Insufficient Security */
MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
MGMT_STATUS_BUSY, /* Role Switch Pending */
MGMT_STATUS_FAILED, /* Slot Violation */
MGMT_STATUS_FAILED, /* Role Switch Failed */
MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
MGMT_STATUS_BUSY, /* Host Busy Pairing */
MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
MGMT_STATUS_BUSY, /* Controller Busy */
MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
};
static u8 mgmt_status(u8 hci_status)
{
if (hci_status < ARRAY_SIZE(mgmt_status_table))
return mgmt_status_table[hci_status];
return MGMT_STATUS_FAILED;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
u16 len, int flag)
{
return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
flag, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 42 | 100.00% | 2 | 100.00% |
Total | 42 | 100.00% | 2 | 100.00% |
static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
u16 len, int flag, struct sock *skip_sk)
{
return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
flag, skip_sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 47 | 100.00% | 1 | 100.00% |
Total | 47 | 100.00% | 1 | 100.00% |
static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
struct sock *skip_sk)
{
return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
HCI_SOCK_TRUSTED, skip_sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 44 | 100.00% | 3 | 100.00% |
Total | 44 | 100.00% | 3 | 100.00% |
static u8 le_addr_type(u8 mgmt_addr_type)
{
if (mgmt_addr_type == BDADDR_LE_PUBLIC)
return ADDR_LE_DEV_PUBLIC;
else
return ADDR_LE_DEV_RANDOM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
void mgmt_fill_version_info(void *ver)
{
struct mgmt_rp_read_version *rp = ver;
rp->version = MGMT_VERSION;
rp->revision = cpu_to_le16(MGMT_REVISION);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 31 | 100.00% | 1 | 100.00% |
Total | 31 | 100.00% | 1 | 100.00% |
static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
struct mgmt_rp_read_version rp;
BT_DBG("sock %p", sk);
mgmt_fill_version_info(&rp);
return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
&rp, sizeof(rp));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 54 | 90.00% | 5 | 62.50% |
Marcel Holtmann | 4 | 6.67% | 2 | 25.00% |
Szymon Janc | 2 | 3.33% | 1 | 12.50% |
Total | 60 | 100.00% | 8 | 100.00% |
static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
struct mgmt_rp_read_commands *rp;
u16 num_commands, num_events;
size_t rp_size;
int i, err;
BT_DBG("sock %p", sk);
if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
num_commands = ARRAY_SIZE(mgmt_commands);
num_events = ARRAY_SIZE(mgmt_events);
} else {
num_commands = ARRAY_SIZE(mgmt_untrusted_commands);
num_events = ARRAY_SIZE(mgmt_untrusted_events);
}
rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
rp = kmalloc(rp_size, GFP_KERNEL);
if (!rp)
return -ENOMEM;
rp->num_commands = cpu_to_le16(num_commands);
rp->num_events = cpu_to_le16(num_events);
if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) {
__le16 *opcode = rp->opcodes;
for (i = 0; i < num_commands; i++, opcode++)
put_unaligned_le16(mgmt_commands[i], opcode);
for (i = 0; i < num_events; i++, opcode++)
put_unaligned_le16(mgmt_events[i], opcode);
} else {
__le16 *opcode = rp->opcodes;
for (i = 0; i < num_commands; i++, opcode++)
put_unaligned_le16(mgmt_untrusted_commands[i], opcode);
for (i = 0; i < num_events; i++, opcode++)
put_unaligned_le16(mgmt_untrusted_events[i], opcode);
}
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
rp, rp_size);
kfree(rp);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 177 | 57.84% | 4 | 57.14% |
Marcel Holtmann | 127 | 41.50% | 2 | 28.57% |
Joe Perches | 2 | 0.65% | 1 | 14.29% |
Total | 306 | 100.00% | 7 | 100.00% |
static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
struct mgmt_rp_read_index_list *rp;
struct hci_dev *d;
size_t rp_len;
u16 count;
int err;
BT_DBG("sock %p", sk);
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (d->dev_type == HCI_PRIMARY &&
!hci_dev_test_flag(d, HCI_UNCONFIGURED))
count++;
}
rp_len = sizeof(*rp) + (2 * count);
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
read_unlock(&hci_dev_list_lock);
return -ENOMEM;
}
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (hci_dev_test_flag(d, HCI_SETUP) ||
hci_dev_test_flag(d, HCI_CONFIG) ||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
continue;
/* Devices marked as raw-only are neither configured
* nor unconfigured controllers.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (d->dev_type == HCI_PRIMARY &&
!hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
rp->index[count++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
}
rp->num_controllers = cpu_to_le16(count);
rp_len = sizeof(*rp) + (2 * count);
read_unlock(&hci_dev_list_lock);
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
0, rp, rp_len);
kfree(rp);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 139 | 50.36% | 7 | 43.75% |
Johan Hedberg | 111 | 40.22% | 6 | 37.50% |
Andrei Emeltchenko | 10 | 3.62% | 1 | 6.25% |
Luiz Augusto von Dentz | 8 | 2.90% | 1 | 6.25% |
Jesper Juhl | 8 | 2.90% | 1 | 6.25% |
Total | 276 | 100.00% | 16 | 100.00% |
static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
struct mgmt_rp_read_unconf_index_list *rp;
struct hci_dev *d;
size_t rp_len;
u16 count;
int err;
BT_DBG("sock %p", sk);
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (d->dev_type == HCI_PRIMARY &&
hci_dev_test_flag(d, HCI_UNCONFIGURED))
count++;
}
rp_len = sizeof(*rp) + (2 * count);
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
read_unlock(&hci_dev_list_lock);
return -ENOMEM;
}
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (hci_dev_test_flag(d, HCI_SETUP) ||
hci_dev_test_flag(d, HCI_CONFIG) ||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
continue;
/* Devices marked as raw-only are neither configured
* nor unconfigured controllers.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (d->dev_type == HCI_PRIMARY &&
hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
rp->index[count++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
}
rp->num_controllers = cpu_to_le16(count);
rp_len = sizeof(*rp) + (2 * count);
read_unlock(&hci_dev_list_lock);
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
kfree(rp);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 199 | 72.63% | 7 | 50.00% |
Johan Hedberg | 71 | 25.91% | 5 | 35.71% |
Szymon Janc | 2 | 0.73% | 1 | 7.14% |
Andrei Emeltchenko | 2 | 0.73% | 1 | 7.14% |
Total | 274 | 100.00% | 14 | 100.00% |
static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
struct mgmt_rp_read_ext_index_list *rp;
struct hci_dev *d;
size_t rp_len;
u16 count;
int err;
BT_DBG("sock %p", sk);
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP)
count++;
}
rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
read_unlock(&hci_dev_list_lock);
return -ENOMEM;
}
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (hci_dev_test_flag(d, HCI_SETUP) ||
hci_dev_test_flag(d, HCI_CONFIG) ||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
continue;
/* Devices marked as raw-only are neither configured
* nor unconfigured controllers.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (d->dev_type == HCI_PRIMARY) {
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
rp->entry[count].type = 0x01;
else
rp->entry[count].type = 0x00;
} else if (d->dev_type == HCI_AMP) {
rp->entry[count].type = 0x02;
} else {
continue;
}
rp->entry[count].bus = d->bus;
rp->entry[count++].index = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
rp->num_controllers = cpu_to_le16(count);
rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
read_unlock(&hci_dev_list_lock);
/* If this command is called at least once, then all the
* default index and unconfigured index events are disabled
* and from now on only extended index events are used.
*/
hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
kfree(rp);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 377 | 100.00% | 2 | 100.00% |
Total | 377 | 100.00% | 2 | 100.00% |
static bool is_configured(struct hci_dev *hdev)
{
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
!hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
return false;
if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
!bacmp(&hdev->public_addr, BDADDR_ANY))
return false;
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 63 | 100.00% | 2 | 100.00% |
Total | 63 | 100.00% | 2 | 100.00% |
static __le32 get_missing_options(struct hci_dev *hdev)
{
u32 options = 0;
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
!hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
options |= MGMT_OPTION_EXTERNAL_CONFIG;
if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
!bacmp(&hdev->public_addr, BDADDR_ANY))
options |= MGMT_OPTION_PUBLIC_ADDRESS;
return cpu_to_le32(options);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 73 | 100.00% | 4 | 100.00% |
Total | 73 | 100.00% | 4 | 100.00% |
static int new_options(struct hci_dev *hdev, struct sock *skip)
{
__le32 options = get_missing_options(hdev);
return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 44 | 100.00% | 2 | 100.00% |
Total | 44 | 100.00% | 2 | 100.00% |
static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
{
__le32 options = get_missing_options(hdev);
return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
sizeof(options));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 48 | 97.96% | 1 | 50.00% |
Johan Hedberg | 1 | 2.04% | 1 | 50.00% |
Total | 49 | 100.00% | 2 | 100.00% |
static int read_config_info(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
struct mgmt_rp_read_config_info rp;
u32 options = 0;
BT_DBG("sock %p %s", sk, hdev->name);
hci_dev_lock(hdev);
memset(&rp, 0, sizeof(rp));
rp.manufacturer = cpu_to_le16(hdev->manufacturer);
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
options |= MGMT_OPTION_EXTERNAL_CONFIG;
if (hdev->set_bdaddr)
options |= MGMT_OPTION_PUBLIC_ADDRESS;
rp.supported_options = cpu_to_le32(options);
rp.missing_options = get_missing_options(hdev);
hci_dev_unlock(hdev);
return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
&rp, sizeof(rp));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marcel Holtmann | 142 | 99.30% | 3 | 75.00% |
Johan Hedberg | 1 | 0.70% | 1 | 25.00% |
Total | 143 | 100.00% | 4 | 100.00% |
static u32 get_supported_settings(struct hci_dev *hdev)
{
u32 settings = 0;
settings |= MGMT_SETTING_POWERED;
settings |= MGMT_SETTING_BONDABLE;
settings |= MGMT_SETTING_DEBUG_KEYS;
settings |= MGMT_SETTING_CONNECTABLE;
settings |= MGMT_SETTING_DISCOVERABLE;
if (lmp_bredr_capable(hdev)) {
if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
settings |= MGMT_SETTING_FAST_CONNECTABLE;
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
if (lmp_ssp_capable(hdev)) {
settings |= MGMT_SETTING_SSP;
settings |= MGMT_SETTING_HS;
}
if (lmp_sc_capable(hdev))
settings |= MGMT_SETTING_SECURE_CONN;
}
if (lmp_le_capable(hdev)) {
settings |= MGMT_SETTING_LE;
settings |= MGMT_SETTING_ADVERTISING;
settings |= MGMT_SETTING_SECURE_CONN;
settings |= MGMT_SETTING_PRIVACY;
settings |= MGMT_SETTING_STATIC_ADDRESS;
}
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
hdev->set_bdaddr)
settings |= MGMT_SETTING_CONFIGURATION;
return settings;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 80 | 55.17% | 13 | 56.52% |
Marcel Holtmann | 59 | 40.69% | 8 | 34.78% |
Andre Guedes | 6 | 4.14% | 2 | 8.70% |
Total | 145 | 100.00% | 23 | 100.00% |
static u32 get_current_settings(struct hci_dev *hdev)
{
u32 settings = 0;
if (hdev_is_powered(hdev))
settings |= MGMT_SETTING_POWERED;
if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
settings |= MGMT_SETTING_CONNECTABLE;
if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
settings |= MGMT_SETTING_FAST_CONNECTABLE;
if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
settings |= MGMT_SETTING_DISCOVERABLE;
if (hci_dev_test_flag(hdev, HCI_BONDABLE))
settings |= MGMT_SETTING_BONDABLE;
if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
settings |= MGMT_SETTING_BREDR;
if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
settings |= MGMT_SETTING_LE;
if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
settings |= MGMT_SETTING_LINK_SECURITY;
if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
settings |= MGMT_SETTING_SSP;
if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
settings |= MGMT_SETTING_HS;
if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
settings |= MGMT_SETTING_ADVERTISING;
if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
settings |= MGMT_SETTING_SECURE_CONN;
if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
settings |= MGMT_SETTING_DEBUG_KEYS;
if (hci_dev_test_flag(hdev, HCI_PRIVACY))
settings |= MGMT_SETTING_PRIVACY;
/* The current setting for static address has two purposes. The
* first is to indicate if the static address will be used and
* the second is to indicate if it is actually set.
*
* This means if the static address is not configured, this flag
* will never be set. If the address is configured, then if the
* address is actually used decides if the flag is set or not.
*
* For single mode LE only controllers and dual-mode controllers
* with BR/EDR disabled, the existence of the static address will
* be evaluated.
*/
if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
!bacmp(&hdev->bdaddr, BDADDR_ANY)) {
if (bacmp(&hdev->static_addr, BDADDR_ANY))
settings |= MGMT_SETTING_STATIC_ADDRESS;
}
return settings;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 134 | 54.47% | 14 | 63.64% |
Marcel Holtmann | 110 | 44.72% | 7 | 31.82% |
Andre Guedes | 2 | 0.81% | 1 | 4.55% |
Total | 246 | 100.00% | 22 | 100.00% |
static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
{
return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 18 | 69.23% | 2 | 50.00% |
Arman Uguray | 4 | 15.38% | 1 | 25.00% |
Marcel Holtmann | 4 | 15.38% | 1 | 25.00% |
Total | 26 | 100.00% | 4 | 100.00% |
static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
struct hci_dev *hdev,
const void *data)
{
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johan Hedberg | 33 | 100.00% | 7 | 100.00% |
Total | 33 | 100.00% | 7 | 100.00% |
u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
/* If there's a pending mgmt command the flags will not yet have
* their final values, so check for this first.
*/
cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
if (cmd) {
struct mgmt_mode *cp = cmd->param;
if (cp->val == 0x01)
return LE_AD_GENERAL;
else if (cp->val