From 4364f2e91f0d44fa0e233d2a55e3ec35053d9bd9 Mon Sep 17 00:00:00 2001 From: Alain Michaud Date: Thu, 23 Apr 2020 14:43:29 +0000 Subject: Bluetooth: allow scatternet connections if supported. This change allows scatternet connections to be created if the controller reports support and the HCI_QUIRK_VALID_LE_STATES indicates that the reported LE states can be trusted. Signed-off-by: Alain Michaud Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 966fc543c01d..006c24e04b44 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5288,7 +5288,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, /* Most controller will fail if we try to create new connections * while we have an existing one in slave role. */ - if (hdev->conn_hash.le_num_slave > 0) + if (hdev->conn_hash.le_num_slave > 0 && + (!test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) || + !(hdev->le_states[3] & 0x10))) return NULL; /* If we're not connectable only connect devices that we have in -- cgit v1.2.3 From eaa7b7228ff7f8688623120bb0cd75d1490d5d04 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Fri, 1 May 2020 10:00:50 -0700 Subject: Bluetooth: Fix advertising handle is set to 0 This patch fix the advertising handle is set to 0 regardless of actual instance value. The affected commands are LE Set Advertising Set Random Address, LE Set Extended Advertising Data, and LE Set Extended Scan Response Data commands. Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 9ea40106ef17..3f470f0e432c 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1447,7 +1447,7 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance) memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data)); hdev->scan_rsp_data_len = len; - cp.handle = 0; + cp.handle = instance; cp.length = len; cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; @@ -1591,7 +1591,7 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance) hdev->adv_data_len = len; cp.length = len; - cp.handle = 0; + cp.handle = instance; cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; @@ -1876,7 +1876,7 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) memset(&cp, 0, sizeof(cp)); - cp.handle = 0; + cp.handle = instance; bacpy(&cp.bdaddr, &random_addr); hci_req_add(req, -- cgit v1.2.3 From 69d67b461a180144ad1d31174fadf3e3eda78e56 Mon Sep 17 00:00:00 2001 From: Konstantin Forostyan Date: Mon, 4 May 2020 16:01:49 +0000 Subject: Bluetooth: L2CAP: Fix errors during L2CAP_CREDIT_BASED_CONNECTION_REQ (0x17) Fix 2 typos in L2CAP_CREDIT_BASED_CONNECTION_REQ (0x17) handling function, that cause BlueZ answer with L2CAP_CR_LE_INVALID_PARAMS or L2CAP_CR_LE_INVALID_SCID error on a correct ECRED connection request. Enchanced Credit Based Mode support was recently introduced with the commit 15f02b91056253e8cdc592888f431da0731337b8 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode"). Signed-off-by: Konstantin Forostyan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fd9d0d08f9c9..fe913a5c754a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5927,7 +5927,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, if (!enable_ecred) return -EINVAL; - if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) { + if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) { result = L2CAP_CR_LE_INVALID_PARAMS; goto response; } @@ -5964,7 +5964,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, } result = L2CAP_CR_LE_SUCCESS; - cmd_len -= sizeof(req); + cmd_len -= sizeof(*req); num_scid = cmd_len / sizeof(u16); for (i = 0; i < num_scid; i++) { -- cgit v1.2.3 From 5f4b91728bba007be563fa5a3bd5d96b6a03b3b9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:46 +0200 Subject: Bluetooth: Add MGMT_EV_PHY_CONFIGURATION_CHANGED to supported list The event MGMT_EV_PHY_CONFIGURATION_CHANGED wasn't listed in the list of supported events. So add it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f8c0a4fc8090..33b5640ea060 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -147,6 +147,7 @@ static const u16 mgmt_events[] = { MGMT_EV_ADVERTISING_ADDED, MGMT_EV_ADVERTISING_REMOVED, MGMT_EV_EXT_INFO_CHANGED, + MGMT_EV_PHY_CONFIGURATION_CHANGED, }; static const u16 mgmt_untrusted_commands[] = { -- cgit v1.2.3 From 181d695352305cc52a49c151a1c3370376e54887 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:47 +0200 Subject: Bluetooth: Replace BT_DBG with bt_dev_dbg for management support The majority of management interaction are based on a controller index and have a hci_dev associated with it. So use bt_dev_dbg to have a clean way of indentifying the controller the debug message belongs to. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 221 +++++++++++++++++++++++++-------------------------- 1 file changed, 110 insertions(+), 111 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 33b5640ea060..78cf72b64014 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -294,7 +294,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_rp_read_version rp; - BT_DBG("sock %p", sk); + bt_dev_dbg(hdev, "sock %p", sk); mgmt_fill_version_info(&rp); @@ -310,7 +310,7 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, size_t rp_size; int i, err; - BT_DBG("sock %p", sk); + bt_dev_dbg(hdev, "sock %p", sk); if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) { num_commands = ARRAY_SIZE(mgmt_commands); @@ -363,7 +363,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, u16 count; int err; - BT_DBG("sock %p", sk); + bt_dev_dbg(hdev, "sock %p", sk); read_lock(&hci_dev_list_lock); @@ -397,7 +397,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, 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); + bt_dev_dbg(hdev, "Added hci%u", d->id); } } @@ -423,7 +423,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, u16 count; int err; - BT_DBG("sock %p", sk); + bt_dev_dbg(hdev, "sock %p", sk); read_lock(&hci_dev_list_lock); @@ -457,7 +457,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, 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); + bt_dev_dbg(hdev, "Added hci%u", d->id); } } @@ -482,7 +482,7 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, u16 count; int err; - BT_DBG("sock %p", sk); + bt_dev_dbg(hdev, "sock %p", sk); read_lock(&hci_dev_list_lock); @@ -524,7 +524,7 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, rp->entry[count].bus = d->bus; rp->entry[count++].index = cpu_to_le16(d->id); - BT_DBG("Added hci%u", d->id); + bt_dev_dbg(hdev, "Added hci%u", d->id); } rp->num_controllers = cpu_to_le16(count); @@ -600,7 +600,7 @@ static int read_config_info(struct sock *sk, struct hci_dev *hdev, struct mgmt_rp_read_config_info rp; u32 options = 0; - BT_DBG("sock %p %s", sk, hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -940,7 +940,7 @@ static void rpa_expired(struct work_struct *work) rpa_expired.work); struct hci_request req; - BT_DBG(""); + bt_dev_dbg(hdev, ""); hci_dev_set_flag(hdev, HCI_RPA_EXPIRED); @@ -980,7 +980,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev, { struct mgmt_rp_read_info rp; - BT_DBG("sock %p %s", sk, hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -1036,7 +1036,7 @@ static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev, struct mgmt_rp_read_ext_info *rp = (void *)buf; u16 eir_len; - BT_DBG("sock %p %s", sk, hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); memset(&buf, 0, sizeof(buf)); @@ -1095,7 +1095,7 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode) { - BT_DBG("%s status 0x%02x", hdev->name, status); + bt_dev_dbg(hdev, "status 0x%02x", status); if (hci_conn_count(hdev) == 0) { cancel_delayed_work(&hdev->power_off); @@ -1171,7 +1171,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_pending_cmd *cmd; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (cp->val != 0x00 && cp->val != 0x01) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, @@ -1312,7 +1312,7 @@ void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status) { struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -1351,7 +1351,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, u16 timeout; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) && !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) @@ -1477,7 +1477,7 @@ void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status) { struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -1537,7 +1537,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_pending_cmd *cmd; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) && !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) @@ -1594,7 +1594,7 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data, bool changed; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (cp->val != 0x00 && cp->val != 0x01) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE, @@ -1638,7 +1638,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, u8 val, status; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); status = mgmt_bredr_support(hdev); if (status) @@ -1706,7 +1706,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) u8 status; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); status = mgmt_bredr_support(hdev); if (status) @@ -1787,7 +1787,7 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) u8 status; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); status = mgmt_bredr_support(hdev); if (status) @@ -1893,7 +1893,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) int err; u8 val, enabled; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, @@ -2054,7 +2054,7 @@ unlock: static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) { - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status); } @@ -2067,7 +2067,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) struct bt_uuid *uuid; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -2133,7 +2133,7 @@ static bool enable_service_cache(struct hci_dev *hdev) static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) { - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status); } @@ -2148,7 +2148,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_request req; int err, found; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -2219,7 +2219,7 @@ unlock: static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode) { - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status); } @@ -2232,7 +2232,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_request req; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_bredr_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, @@ -2305,7 +2305,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, bool changed; int i; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_bredr_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, @@ -2331,8 +2331,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); - BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, - key_count); + bt_dev_dbg(hdev, "debug_keys %u key_count %u", cp->debug_keys, + key_count); for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; @@ -2533,7 +2533,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -2617,7 +2617,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, int err; u16 i; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -2693,7 +2693,7 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_pending_cmd *cmd; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -2751,7 +2751,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_set_io_capability *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, @@ -2761,8 +2761,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, hdev->io_capability = cp->io_capability; - BT_DBG("%s IO capability set to 0x%02x", hdev->name, - hdev->io_capability); + bt_dev_dbg(hdev, "IO capability set to 0x%02x", hdev->io_capability); hci_dev_unlock(hdev); @@ -2874,7 +2873,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -3003,7 +3002,7 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -3114,7 +3113,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, { struct mgmt_cp_pin_code_neg_reply *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); return user_pairing_resp(sk, hdev, &cp->addr, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -3126,7 +3125,7 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_user_confirm_reply *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); if (len != sizeof(*cp)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, @@ -3142,7 +3141,7 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, { struct mgmt_cp_user_confirm_neg_reply *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); return user_pairing_resp(sk, hdev, &cp->addr, MGMT_OP_USER_CONFIRM_NEG_REPLY, @@ -3154,7 +3153,7 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_user_passkey_reply *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); return user_pairing_resp(sk, hdev, &cp->addr, MGMT_OP_USER_PASSKEY_REPLY, @@ -3166,7 +3165,7 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, { struct mgmt_cp_user_passkey_neg_reply *cp = data; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); return user_pairing_resp(sk, hdev, &cp->addr, MGMT_OP_USER_PASSKEY_NEG_REPLY, @@ -3207,7 +3206,7 @@ static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode) struct mgmt_cp_set_local_name *cp; struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -3242,7 +3241,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_request req; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -3311,7 +3310,7 @@ static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data, u16 appearance; int err; - BT_DBG(""); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE, @@ -3343,7 +3342,7 @@ static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev, { struct mgmt_rp_get_phy_confguration rp; - BT_DBG("sock %p %s", sk, hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -3376,7 +3375,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, u8 status, { struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -3414,7 +3413,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev, bool changed = false; int err; - BT_DBG("sock %p %s", sk, hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); configurable_phys = get_configurable_phys(hdev); supported_phys = get_supported_phys(hdev); @@ -3567,7 +3566,7 @@ static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 key_count, expected_len; int i; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); key_count = __le16_to_cpu(keys->key_count); if (key_count > max_key_count) { @@ -3613,7 +3612,7 @@ static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev, int err; bool changed = false; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks)) return mgmt_cmd_status(sk, hdev->id, @@ -3718,7 +3717,7 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, size_t rp_size = sizeof(mgmt_rp); struct mgmt_pending_cmd *cmd; - BT_DBG("%s status %u", hdev->name, status); + bt_dev_dbg(hdev, "status %u", status); cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev); if (!cmd) @@ -3777,7 +3776,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, struct hci_request req; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -3827,7 +3826,7 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, struct mgmt_addr_info *addr = data; int err; - BT_DBG("%s ", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!bdaddr_type_is_valid(addr->type)) return mgmt_cmd_complete(sk, hdev->id, @@ -3936,7 +3935,7 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, u8 status; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (cp->addr.type != BDADDR_BREDR) return mgmt_cmd_complete(sk, hdev->id, @@ -3970,7 +3969,7 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status) { struct mgmt_pending_cmd *cmd; - BT_DBG("status %d", status); + bt_dev_dbg(hdev, "status %d", status); hci_dev_lock(hdev); @@ -4031,7 +4030,7 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev, u8 status; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -4123,7 +4122,7 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev, u8 status; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -4218,7 +4217,7 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status) { struct mgmt_pending_cmd *cmd; - BT_DBG("status %d", status); + bt_dev_dbg(hdev, "status %d", status); hci_dev_lock(hdev); @@ -4244,7 +4243,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_pending_cmd *cmd; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -4286,7 +4285,7 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, struct inquiry_entry *e; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -4328,7 +4327,7 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, u8 status; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!bdaddr_type_is_valid(cp->addr.type)) return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, @@ -4364,7 +4363,7 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, u8 status; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!bdaddr_type_is_valid(cp->addr.type)) return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, @@ -4401,7 +4400,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, int err; __u16 source; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); source = __le16_to_cpu(cp->source); @@ -4431,7 +4430,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, static void enable_advertising_instance(struct hci_dev *hdev, u8 status, u16 opcode) { - BT_DBG("status %d", status); + bt_dev_dbg(hdev, "status %d", status); } static void set_advertising_complete(struct hci_dev *hdev, u8 status, @@ -4517,7 +4516,7 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u8 val, status; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); status = mgmt_le_support(hdev); if (status) @@ -4626,7 +4625,7 @@ static int set_static_address(struct sock *sk, struct hci_dev *hdev, struct mgmt_cp_set_static_address *cp = data; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, @@ -4671,7 +4670,7 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev, __u16 interval, window; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, @@ -4726,7 +4725,7 @@ static void fast_connectable_complete(struct hci_dev *hdev, u8 status, { struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -4763,7 +4762,7 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, struct hci_request req; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) || hdev->hci_ver < BLUETOOTH_VER_1_2) @@ -4824,7 +4823,7 @@ static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct mgmt_pending_cmd *cmd; - BT_DBG("status 0x%02x", status); + bt_dev_dbg(hdev, "status 0x%02x", status); hci_dev_lock(hdev); @@ -4859,7 +4858,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) struct hci_request req; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR, @@ -4969,7 +4968,7 @@ static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode) struct mgmt_pending_cmd *cmd; struct mgmt_mode *cp; - BT_DBG("%s status %u", hdev->name, status); + bt_dev_dbg(hdev, "status %u", status); hci_dev_lock(hdev); @@ -5018,7 +5017,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, u8 val; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_sc_capable(hdev) && !hci_dev_test_flag(hdev, HCI_LE_ENABLED)) @@ -5104,7 +5103,7 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, bool changed, use_changed; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, @@ -5151,7 +5150,7 @@ static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data, bool changed; int err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, @@ -5226,7 +5225,7 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 irk_count, expected_len; int i, err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, @@ -5248,7 +5247,7 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, MGMT_STATUS_INVALID_PARAMS); } - BT_DBG("%s irk_count %u", hdev->name, irk_count); + bt_dev_dbg(hdev, "irk_count %u", irk_count); for (i = 0; i < irk_count; i++) { struct mgmt_irk_info *key = &cp->irks[i]; @@ -5316,7 +5315,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, u16 key_count, expected_len; int i, err; - BT_DBG("request for %s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, @@ -5338,7 +5337,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, MGMT_STATUS_INVALID_PARAMS); } - BT_DBG("%s key_count %u", hdev->name, key_count); + bt_dev_dbg(hdev, "key_count %u", key_count); for (i = 0; i < key_count; i++) { struct mgmt_ltk_info *key = &cp->keys[i]; @@ -5439,7 +5438,7 @@ static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status, u16 handle; u8 status; - BT_DBG("status 0x%02x", hci_status); + bt_dev_dbg(hdev, "status 0x%02x", hci_status); hci_dev_lock(hdev); @@ -5493,7 +5492,7 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, unsigned long conn_info_age; int err = 0; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -5647,7 +5646,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode) struct mgmt_pending_cmd *cmd; struct hci_conn *conn; - BT_DBG("%s status %u", hdev->name, status); + bt_dev_dbg(hdev, "status %u", status); hci_dev_lock(hdev); @@ -5684,7 +5683,7 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -5805,8 +5804,8 @@ static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, params->auto_connect = auto_connect; - BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type, - auto_connect); + bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u", + addr, addr_type, auto_connect); return 0; } @@ -5830,7 +5829,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, u8 auto_conn, addr_type; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!bdaddr_type_is_valid(cp->addr.type) || !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) @@ -5928,7 +5927,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, struct mgmt_cp_remove_device *cp = data; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -6037,7 +6036,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, kfree(p); } - BT_DBG("All LE connection parameters were removed"); + bt_dev_dbg(hdev, "All LE connection parameters were removed"); hci_update_background_scan(hdev); } @@ -6080,7 +6079,7 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, MGMT_STATUS_INVALID_PARAMS); } - BT_DBG("%s param_count %u", hdev->name, param_count); + bt_dev_dbg(hdev, "param_count %u", param_count); hci_dev_lock(hdev); @@ -6092,8 +6091,8 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, u16 min, max, latency, timeout; u8 addr_type; - BT_DBG("Adding %pMR (type %u)", ¶m->addr.bdaddr, - param->addr.type); + bt_dev_dbg(hdev, "Adding %pMR (type %u)", ¶m->addr.bdaddr, + param->addr.type); if (param->addr.type == BDADDR_LE_PUBLIC) { addr_type = ADDR_LE_DEV_PUBLIC; @@ -6109,8 +6108,8 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, latency = le16_to_cpu(param->latency); timeout = le16_to_cpu(param->timeout); - BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x", - min, max, latency, timeout); + bt_dev_dbg(hdev, "min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x", + min, max, latency, timeout); if (hci_check_conn_params(min, max, latency, timeout) < 0) { bt_dev_err(hdev, "ignoring invalid connection parameters"); @@ -6143,7 +6142,7 @@ static int set_external_config(struct sock *sk, struct hci_dev *hdev, bool changed; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (hdev_is_powered(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, @@ -6199,7 +6198,7 @@ static int set_public_address(struct sock *sk, struct hci_dev *hdev, bool changed; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (hdev_is_powered(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, @@ -6254,7 +6253,7 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, u16 eir_len; int err; - BT_DBG("%s status %u", hdev->name, status); + bt_dev_dbg(hdev, "status %u", status); cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev); if (!cmd) @@ -6393,7 +6392,7 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, u8 status, flags, role, addr[7], hash[16], rand[16]; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (hdev_is_powered(hdev)) { switch (cp->type) { @@ -6580,7 +6579,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, u32 supported_flags; u8 *instance; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES, @@ -6723,7 +6722,7 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status, struct adv_info *adv_instance, *n; u8 instance; - BT_DBG("status %d", status); + bt_dev_dbg(hdev, "status %d", status); hci_dev_lock(hdev); @@ -6782,7 +6781,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, struct mgmt_pending_cmd *cmd; struct hci_request req; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); status = mgmt_le_support(hdev); if (status) @@ -6919,7 +6918,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status, struct mgmt_cp_remove_advertising *cp; struct mgmt_rp_remove_advertising rp; - BT_DBG("status %d", status); + bt_dev_dbg(hdev, "status %d", status); hci_dev_lock(hdev); @@ -6951,7 +6950,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev, struct hci_request req; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); hci_dev_lock(hdev); @@ -7023,7 +7022,7 @@ static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev, u32 flags, supported_flags; int err; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "sock %p", sk); if (!lmp_le_capable(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO, @@ -7251,7 +7250,7 @@ void mgmt_power_on(struct hci_dev *hdev, int err) { struct cmd_lookup match = { NULL, hdev }; - BT_DBG("err %d", err); + bt_dev_dbg(hdev, "err %d", err); hci_dev_lock(hdev); @@ -7670,7 +7669,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct mgmt_ev_user_confirm_request ev; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr); bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(link_type, addr_type); @@ -7686,7 +7685,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct mgmt_ev_user_passkey_request ev; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr); bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(link_type, addr_type); @@ -7747,7 +7746,7 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct mgmt_ev_passkey_notify ev; - BT_DBG("%s", hdev->name); + bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr); bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(link_type, addr_type); @@ -8166,7 +8165,7 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering) { struct mgmt_ev_discovering ev; - BT_DBG("%s discovering %u", hdev->name, discovering); + bt_dev_dbg(hdev, "discovering %u", discovering); memset(&ev, 0, sizeof(ev)); ev.type = hdev->discovery.type; -- cgit v1.2.3 From d5cc6626b33780699c7a4986f3521361306862fe Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:49 +0200 Subject: Bluetooth: Introduce HCI_MGMT_HDEV_OPTIONAL option When setting HCI_MGMT_HDEV_OPTIONAL it is possible to target a specific conntroller or a global interface. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_sock.c | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 239ab72f16c6..0c7f3ad76665 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1554,6 +1554,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); #define HCI_MGMT_NO_HDEV BIT(1) #define HCI_MGMT_UNTRUSTED BIT(2) #define HCI_MGMT_UNCONFIGURED BIT(3) +#define HCI_MGMT_HDEV_OPTIONAL BIT(4) struct hci_mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 9c4a093f8960..caf38a8ea6a8 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1579,11 +1579,13 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk, } } - no_hdev = (handler->flags & HCI_MGMT_NO_HDEV); - if (no_hdev != !hdev) { - err = mgmt_cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_INDEX); - goto done; + if (!(handler->flags & HCI_MGMT_HDEV_OPTIONAL)) { + no_hdev = (handler->flags & HCI_MGMT_NO_HDEV); + if (no_hdev != !hdev) { + err = mgmt_cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_INDEX); + goto done; + } } var_len = (handler->flags & HCI_MGMT_VAR_LEN); -- cgit v1.2.3 From 568602457c1ab6d26db828de168e4ef35b88f1bc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:50 +0200 Subject: Bluetooth: Replace BT_DBG with bt_dev_dbg for security manager support The security manager operates on a specific controller and thus use bt_dev_dbg to indetify the controller for each debug message. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index df22cbf94693..5510017cf9ff 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -508,7 +508,7 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16], if (!chan || !chan->data) return false; - BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); + bt_dev_dbg(hdev, "RPA %pMR IRK %*phN", bdaddr, 16, irk); err = smp_ah(irk, &bdaddr->b[3], hash); if (err) @@ -534,7 +534,7 @@ int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa) if (err < 0) return err; - BT_DBG("RPA %pMR", rpa); + bt_dev_dbg(hdev, "RPA %pMR", rpa); return 0; } @@ -551,7 +551,7 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) smp = chan->data; if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { - BT_DBG("Using debug keys"); + bt_dev_dbg(hdev, "Using debug keys"); err = set_ecdh_privkey(smp->tfm_ecdh, debug_sk); if (err) return err; @@ -1867,7 +1867,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) { struct hci_dev *hdev = smp->conn->hcon->hdev; - BT_DBG(""); + bt_dev_dbg(hdev, ""); if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) { struct l2cap_chan *chan = hdev->smp_data; -- cgit v1.2.3 From a10c907ce0e5e138c3da091fcb7c3d109a15aec5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:51 +0200 Subject: Bluetooth: Add support for experimental features configuration To enable platform specific experimental features, introduce this new set of management commands and events. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 27 +++++++++++++++++++++ net/bluetooth/mgmt.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e5bc1dfe809a..16ab6ce87883 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -258,6 +258,7 @@ enum { HCI_MGMT_DEV_CLASS_EVENTS, HCI_MGMT_LOCAL_NAME_EVENTS, HCI_MGMT_OOB_DATA_EVENTS, + HCI_MGMT_EXP_FEATURE_EVENTS, }; /* diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 9d4d87c6028e..16e0d87bd8fa 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -681,6 +681,27 @@ struct mgmt_rp_read_security_info { __u8 sec[]; } __packed; +#define MGMT_OP_READ_EXP_FEATURES_INFO 0x0049 +#define MGMT_READ_EXP_FEATURES_INFO_SIZE 0 +struct mgmt_rp_read_exp_features_info { + __le16 feature_count; + struct { + __u8 uuid[16]; + __le32 flags; + } features[]; +} __packed; + +#define MGMT_OP_SET_EXP_FEATURE 0x004a +struct mgmt_cp_set_exp_feature { + __u8 uuid[16]; + __u8 param[]; +} __packed; +#define MGMT_SET_EXP_FEATURE_SIZE 16 +struct mgmt_rp_set_exp_feature { + __u8 uuid[16]; + __le32 flags; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; @@ -906,3 +927,9 @@ struct mgmt_ev_ext_info_changed { struct mgmt_ev_phy_configuration_changed { __le32 selected_phys; } __packed; + +#define MGMT_EV_EXP_FEATURE_CHANGED 0x0027 +struct mgmt_ev_exp_feature_changed { + __u8 uuid[16]; + __le32 flags; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 78cf72b64014..3c6be70d98ef 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -109,6 +109,8 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_BLOCKED_KEYS, MGMT_OP_SET_WIDEBAND_SPEECH, MGMT_OP_READ_SECURITY_INFO, + MGMT_OP_READ_EXP_FEATURES_INFO, + MGMT_OP_SET_EXP_FEATURE, }; static const u16 mgmt_events[] = { @@ -148,6 +150,7 @@ static const u16 mgmt_events[] = { MGMT_EV_ADVERTISING_REMOVED, MGMT_EV_EXT_INFO_CHANGED, MGMT_EV_PHY_CONFIGURATION_CHANGED, + MGMT_EV_EXP_FEATURE_CHANGED, }; static const u16 mgmt_untrusted_commands[] = { @@ -158,6 +161,7 @@ static const u16 mgmt_untrusted_commands[] = { MGMT_OP_READ_EXT_INDEX_LIST, MGMT_OP_READ_EXT_INFO, MGMT_OP_READ_SECURITY_INFO, + MGMT_OP_READ_EXP_FEATURES_INFO, }; static const u16 mgmt_untrusted_events[] = { @@ -172,6 +176,7 @@ static const u16 mgmt_untrusted_events[] = { MGMT_EV_EXT_INDEX_ADDED, MGMT_EV_EXT_INDEX_REMOVED, MGMT_EV_EXT_INFO_CHANGED, + MGMT_EV_EXP_FEATURE_CHANGED, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -3710,6 +3715,53 @@ static int read_security_info(struct sock *sk, struct hci_dev *hdev, rp, sizeof(*rp) + sec_len); } +static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) +{ + char buf[42]; + struct mgmt_rp_read_exp_features_info *rp = (void *)buf; + u16 idx = 0; + + bt_dev_dbg(hdev, "sock %p", sk); + + memset(&buf, 0, sizeof(buf)); + + rp->feature_count = cpu_to_le16(idx); + + /* After reading the experimental features information, enable + * the events to update client on any future change. + */ + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); + + return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, + MGMT_OP_READ_EXP_FEATURES_INFO, + 0, rp, sizeof(*rp) + (20 * idx)); +} + +static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) +{ + struct mgmt_cp_set_exp_feature *cp = data; + struct mgmt_rp_set_exp_feature rp; + + bt_dev_dbg(hdev, "sock %p", sk); + + if (!memcmp(cp->uuid, ZERO_KEY, 16)) { + memset(rp.uuid, 0, 16); + rp.flags = cpu_to_le32(0); + + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); + + return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, 0, + &rp, sizeof(rp)); + } + + return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_NOT_SUPPORTED); +} + static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, u16 opcode, struct sk_buff *skb) { @@ -7152,6 +7204,12 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { set_wideband_speech, MGMT_SETTING_SIZE }, { read_security_info, MGMT_READ_SECURITY_INFO_SIZE, HCI_MGMT_UNTRUSTED }, + { read_exp_features_info, MGMT_READ_EXP_FEATURES_INFO_SIZE, + HCI_MGMT_UNTRUSTED | + HCI_MGMT_HDEV_OPTIONAL }, + { set_exp_feature, MGMT_SET_EXP_FEATURE_SIZE, + HCI_MGMT_VAR_LEN | + HCI_MGMT_HDEV_OPTIONAL }, }; void mgmt_index_added(struct hci_dev *hdev) -- cgit v1.2.3 From e625e50ceee18bc1e3fb1a6375e089405a797a4d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 6 May 2020 09:57:52 +0200 Subject: Bluetooth: Introduce debug feature when dynamic debug is disabled In case dynamic debug is disabled, this feature allows a vendor platform to provide debug statement printing. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 11 +++++ net/bluetooth/Kconfig | 7 ++++ net/bluetooth/lib.c | 33 +++++++++++++++ net/bluetooth/mgmt.c | 87 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3fa7b1e3c5d9..18190055374c 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -153,6 +153,12 @@ __printf(1, 2) void bt_warn(const char *fmt, ...); __printf(1, 2) void bt_err(const char *fmt, ...); +#if IS_ENABLED(CONFIG_BT_FEATURE_DEBUG) +void bt_dbg_set(bool enable); +bool bt_dbg_get(void); +__printf(1, 2) +void bt_dbg(const char *fmt, ...); +#endif __printf(1, 2) void bt_warn_ratelimited(const char *fmt, ...); __printf(1, 2) @@ -161,7 +167,12 @@ void bt_err_ratelimited(const char *fmt, ...); #define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__) #define BT_WARN(fmt, ...) bt_warn(fmt "\n", ##__VA_ARGS__) #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) + +#if IS_ENABLED(CONFIG_BT_FEATURE_DEBUG) +#define BT_DBG(fmt, ...) bt_dbg(fmt "\n", ##__VA_ARGS__) +#else #define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) +#endif #define bt_dev_info(hdev, fmt, ...) \ BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 9e25c6570170..1d6d243cdde9 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -135,4 +135,11 @@ config BT_SELFTEST_SMP Run test cases for SMP cryptographic functionality, including both legacy SMP as well as the Secure Connections features. +config BT_FEATURE_DEBUG + bool "Enable runtime option for debugging statements" + depends on BT && !DYNAMIC_DEBUG + help + This provides an option to enable/disable debugging statements + at runtime via the experimental features interface. + source "drivers/bluetooth/Kconfig" diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index c09e0a3a0ed9..5326f41a58b7 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -183,6 +183,39 @@ void bt_err(const char *format, ...) } EXPORT_SYMBOL(bt_err); +#ifdef CONFIG_BT_FEATURE_DEBUG +static bool debug_enable; + +void bt_dbg_set(bool enable) +{ + debug_enable = enable; +} + +bool bt_dbg_get(void) +{ + return debug_enable; +} + +void bt_dbg(const char *format, ...) +{ + struct va_format vaf; + va_list args; + + if (likely(!debug_enable)) + return; + + va_start(args, format); + + vaf.fmt = format; + vaf.va = &args; + + printk(KERN_DEBUG pr_fmt("%pV"), &vaf); + + va_end(args); +} +EXPORT_SYMBOL(bt_dbg); +#endif + void bt_warn_ratelimited(const char *format, ...) { struct va_format vaf; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3c6be70d98ef..9e8a3cccc6ca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3715,6 +3715,14 @@ static int read_security_info(struct sock *sk, struct hci_dev *hdev, rp, sizeof(*rp) + sec_len); } +#ifdef CONFIG_BT_FEATURE_DEBUG +/* d4992530-b9ec-469f-ab01-6c481c47da1c */ +static const u8 debug_uuid[16] = { + 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab, + 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4, +}; +#endif + static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { @@ -3726,6 +3734,16 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, memset(&buf, 0, sizeof(buf)); +#ifdef CONFIG_BT_FEATURE_DEBUG + if (!hdev) { + u32 flags = bt_dbg_get() ? BIT(0) : 0; + + memcpy(rp->features[idx].uuid, debug_uuid, 16); + rp->features[idx].flags = cpu_to_le32(flags); + idx++; + } +#endif + rp->feature_count = cpu_to_le16(idx); /* After reading the experimental features information, enable @@ -3738,6 +3756,21 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, 0, rp, sizeof(*rp) + (20 * idx)); } +#ifdef CONFIG_BT_FEATURE_DEBUG +static int exp_debug_feature_changed(bool enabled, struct sock *skip) +{ + struct mgmt_ev_exp_feature_changed ev; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.uuid, debug_uuid, 16); + ev.flags = cpu_to_le32(enabled ? BIT(0) : 0); + + return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL, + &ev, sizeof(ev), + HCI_MGMT_EXP_FEATURE_EVENTS, skip); +} +#endif + static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { @@ -3750,6 +3783,17 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, memset(rp.uuid, 0, 16); rp.flags = cpu_to_le32(0); +#ifdef CONFIG_BT_FEATURE_DEBUG + if (!hdev) { + bool changed = bt_dbg_get(); + + bt_dbg_set(false); + + if (changed) + exp_debug_feature_changed(false, sk); + } +#endif + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); return mgmt_cmd_complete(sk, hdev ? hdev->id : MGMT_INDEX_NONE, @@ -3757,6 +3801,49 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev, &rp, sizeof(rp)); } +#ifdef CONFIG_BT_FEATURE_DEBUG + if (!memcmp(cp->uuid, debug_uuid, 16)) { + bool val, changed; + int err; + + /* Command requires to use the non-controller index */ + if (hdev) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_INDEX); + + /* Parameters are limited to a single octet */ + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_PARAMS); + + /* Only boolean on/off is supported */ + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_PARAMS); + + val = !!cp->param[0]; + changed = val ? !bt_dbg_get() : bt_dbg_get(); + bt_dbg_set(val); + + memcpy(rp.uuid, debug_uuid, 16); + rp.flags = cpu_to_le32(val ? BIT(0) : 0); + + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); + + err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, 0, + &rp, sizeof(rp)); + + if (changed) + exp_debug_feature_changed(val, sk); + + return err; + } +#endif + return mgmt_cmd_status(sk, hdev ? hdev->id : MGMT_INDEX_NONE, MGMT_OP_SET_EXP_FEATURE, MGMT_STATUS_NOT_SUPPORTED); -- cgit v1.2.3 From aaebf8e6088270e45d30314031b5d9a88a589cb9 Mon Sep 17 00:00:00 2001 From: Abhishek Pandit-Subedi Date: Tue, 12 May 2020 19:09:32 -0700 Subject: Bluetooth: Fix incorrect type for window and interval The types for window and interval should be uint16, not uint8. Signed-off-by: Abhishek Pandit-Subedi Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 3f470f0e432c..f6870e98faab 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -890,7 +890,7 @@ void hci_req_add_le_passive_scan(struct hci_request *req) struct hci_dev *hdev = req->hdev; u8 own_addr_type; u8 filter_policy; - u8 window, interval; + u16 window, interval; if (hdev->scanning_paused) { bt_dev_dbg(hdev, "Scanning is paused for suspend"); -- cgit v1.2.3 From 91779665c129d361c032d2a590b37a077b6cb9d7 Mon Sep 17 00:00:00 2001 From: Abhishek Pandit-Subedi Date: Tue, 12 May 2020 19:09:33 -0700 Subject: Bluetooth: Modify LE window and interval for suspend When a device is suspended, it doesn't need to be as responsive to connection events. Increase the interval to 640ms (creating a duty cycle of roughly 1.75%) so that passive scanning uses much less power (vs previous duty cycle of 18.75%). The new window + interval combination has been tested to work with HID devices (which are currently the only devices capable of wake up). Signed-off-by: Abhishek Pandit-Subedi Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index f6870e98faab..6b45e31432a7 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -35,7 +35,7 @@ #define HCI_REQ_CANCELED 2 #define LE_SUSPEND_SCAN_WINDOW 0x0012 -#define LE_SUSPEND_SCAN_INTERVAL 0x0060 +#define LE_SUSPEND_SCAN_INTERVAL 0x0400 void hci_req_init(struct hci_request *req, struct hci_dev *hdev) { -- cgit v1.2.3 From 0d2c9825e46d45f8a520135c9c791b5c73a165ab Mon Sep 17 00:00:00 2001 From: Abhishek Pandit-Subedi Date: Tue, 12 May 2020 19:19:25 -0700 Subject: Bluetooth: Rename BT_SUSPEND_COMPLETE Renamed BT_SUSPEND_COMPLETE to BT_SUSPEND_CONFIGURE_WAKE since it sets up the event filter and whitelist for wake-up. Signed-off-by: Abhishek Pandit-Subedi Reviewed-by: Alain Michaud Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 2 +- net/bluetooth/hci_request.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0c7f3ad76665..869ee2b30a4c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -110,7 +110,7 @@ enum suspend_tasks { enum suspended_state { BT_RUNNING = 0, BT_SUSPEND_DISCONNECT, - BT_SUSPEND_COMPLETE, + BT_SUSPEND_CONFIGURE_WAKE, }; struct hci_conn_hash { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 51d399273276..de1f4e72ec06 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3353,7 +3353,7 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, /* Only configure whitelist if disconnect succeeded */ if (!ret) ret = hci_change_suspend_state(hdev, - BT_SUSPEND_COMPLETE); + BT_SUSPEND_CONFIGURE_WAKE); } else if (action == PM_POST_SUSPEND) { ret = hci_change_suspend_state(hdev, BT_RUNNING); } diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 6b45e31432a7..1fc55685da62 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1090,7 +1090,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next) disconnect_counter); set_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks); } - } else if (next == BT_SUSPEND_COMPLETE) { + } else if (next == BT_SUSPEND_CONFIGURE_WAKE) { /* Unpause to take care of updating scanning params */ hdev->scanning_paused = false; /* Enable event filter for paired devices */ -- cgit v1.2.3 From 81dafad53c67abe4f09b0b04131fe490e76e5602 Mon Sep 17 00:00:00 2001 From: Abhishek Pandit-Subedi Date: Tue, 12 May 2020 19:19:26 -0700 Subject: Bluetooth: Add hook for driver to prevent wake from suspend Let drivers have a hook to disable configuring scanning during suspend. Drivers should use the device_may_wakeup function call to determine whether hci should be configured for wakeup. For example, an implementation for btusb may look like the following: bool btusb_prevent_wake(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); return !device_may_wakeup(&data->udev->dev); } Signed-off-by: Abhishek Pandit-Subedi Reviewed-by: Alain Michaud Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 869ee2b30a4c..5dcf85f186c6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -503,6 +503,7 @@ struct hci_dev { int (*set_diag)(struct hci_dev *hdev, bool enable); int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr); void (*cmd_timeout)(struct hci_dev *hdev); + bool (*prevent_wake)(struct hci_dev *hdev); }; #define HCI_PHY_HANDLE(handle) (handle & 0xff) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index de1f4e72ec06..dbe2d79f233f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3350,8 +3350,10 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, */ ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT); - /* Only configure whitelist if disconnect succeeded */ - if (!ret) + /* Only configure whitelist if disconnect succeeded and wake + * isn't being prevented. + */ + if (!ret && !(hdev->prevent_wake && hdev->prevent_wake(hdev))) ret = hci_change_suspend_state(hdev, BT_SUSPEND_CONFIGURE_WAKE); } else if (action == PM_POST_SUSPEND) { -- cgit v1.2.3 From adf1d6926444029396861413aba8a0f2a805742a Mon Sep 17 00:00:00 2001 From: Sonny Sasaka Date: Wed, 6 May 2020 12:55:03 -0700 Subject: Bluetooth: Handle Inquiry Cancel error after Inquiry Complete After sending Inquiry Cancel command to the controller, it is possible that Inquiry Complete event comes before Inquiry Cancel command complete event. In this case the Inquiry Cancel command will have status of Command Disallowed since there is no Inquiry session to be cancelled. This case should not be treated as error, otherwise we can reach an inconsistent state. Example of a btmon trace when this happened: < HCI Command: Inquiry Cancel (0x01|0x0002) plen 0 > HCI Event: Inquiry Complete (0x01) plen 1 Status: Success (0x00) > HCI Event: Command Complete (0x0e) plen 4 Inquiry Cancel (0x01|0x0002) ncmd 1 Status: Command Disallowed (0x0c) Signed-off-by: Sonny Sasaka Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 006c24e04b44..73aabca0064b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -42,12 +42,27 @@ /* Handle HCI Event packets */ -static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb, + u8 *new_status) { __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%2.2x", hdev->name, status); + /* It is possible that we receive Inquiry Complete event right + * before we receive Inquiry Cancel Command Complete event, in + * which case the latter event should have status of Command + * Disallowed (0x0c). This should not be treated as error, since + * we actually achieve what Inquiry Cancel wants to achieve, + * which is to end the last Inquiry session. + */ + if (status == 0x0c && !test_bit(HCI_INQUIRY, &hdev->flags)) { + bt_dev_warn(hdev, "Ignoring error of Inquiry Cancel command"); + status = 0x00; + } + + *new_status = status; + if (status) return; @@ -3233,7 +3248,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, switch (*opcode) { case HCI_OP_INQUIRY_CANCEL: - hci_cc_inquiry_cancel(hdev, skb); + hci_cc_inquiry_cancel(hdev, skb, status); break; case HCI_OP_PERIODIC_INQ: -- cgit v1.2.3 From 5b440676c15bbe1a40f2546ec92db83ed66d9e22 Mon Sep 17 00:00:00 2001 From: Archie Pusaka Date: Tue, 14 Apr 2020 16:08:40 +0800 Subject: Bluetooth: L2CAP: add support for waiting disconnection resp Whenever we disconnect a L2CAP connection, we would immediately report a disconnection event (EPOLLHUP) to the upper layer, without waiting for the response of the other device. This patch offers an option to wait until we receive a disconnection response before reporting disconnection event, by using the "how" parameter in l2cap_sock_shutdown(). Therefore, upper layer can opt to wait for disconnection response by shutdown(sock, SHUT_WR). This can be used to enforce proper disconnection order in HID, where the disconnection of the interrupt channel must be complete before attempting to disconnect the control channel. Signed-off-by: Archie Pusaka Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1cea42ee1e92..a995d2c51fa7 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1271,14 +1271,21 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) struct l2cap_conn *conn; int err = 0; - BT_DBG("sock %p, sk %p", sock, sk); + BT_DBG("sock %p, sk %p, how %d", sock, sk, how); + + /* 'how' parameter is mapped to sk_shutdown as follows: + * SHUT_RD (0) --> RCV_SHUTDOWN (1) + * SHUT_WR (1) --> SEND_SHUTDOWN (2) + * SHUT_RDWR (2) --> SHUTDOWN_MASK (3) + */ + how++; if (!sk) return 0; lock_sock(sk); - if (sk->sk_shutdown) + if ((sk->sk_shutdown & how) == how) goto shutdown_already; BT_DBG("Handling sock shutdown"); @@ -1301,11 +1308,20 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) * has already been actioned to close the L2CAP * link such as by l2cap_disconnection_req(). */ - if (sk->sk_shutdown) - goto has_shutdown; + if ((sk->sk_shutdown & how) == how) + goto shutdown_matched; } - sk->sk_shutdown = SHUTDOWN_MASK; + /* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN + * is already set + */ + if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) { + sk->sk_shutdown |= RCV_SHUTDOWN; + if ((sk->sk_shutdown & how) == how) + goto shutdown_matched; + } + + sk->sk_shutdown |= SEND_SHUTDOWN; release_sock(sk); l2cap_chan_lock(chan); @@ -1335,7 +1351,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); -has_shutdown: +shutdown_matched: l2cap_chan_put(chan); sock_put(sk); @@ -1363,7 +1379,7 @@ static int l2cap_sock_release(struct socket *sock) bt_sock_unlink(&l2cap_sk_list, sk); - err = l2cap_sock_shutdown(sock, 2); + err = l2cap_sock_shutdown(sock, SHUT_RDWR); chan = l2cap_pi(sk)->chan; l2cap_chan_hold(chan); -- cgit v1.2.3