/net/bluetooth/hci_event.c
http://github.com/mirrors/linux · C · 6167 lines · 4315 code · 1438 blank · 414 comment · 824 complexity · 20943b43737aa6ea0cb07baf7990615a MD5 · raw file
Large files are truncated click here to view the full file
- /*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
- 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 event handling. */
- #include <asm/unaligned.h>
- #include <net/bluetooth/bluetooth.h>
- #include <net/bluetooth/hci_core.h>
- #include <net/bluetooth/mgmt.h>
- #include "hci_request.h"
- #include "hci_debugfs.h"
- #include "a2mp.h"
- #include "amp.h"
- #include "smp.h"
- #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- /* Handle HCI Event packets */
- static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- clear_bit(HCI_INQUIRY, &hdev->flags);
- smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */
- wake_up_bit(&hdev->flags, HCI_INQUIRY);
- hci_dev_lock(hdev);
- /* Set discovery state to stopped if we're not doing LE active
- * scanning.
- */
- if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
- hdev->le_scan_type != LE_SCAN_ACTIVE)
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
- hci_conn_check_pending(hdev);
- }
- static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- hci_dev_set_flag(hdev, HCI_PERIODIC_INQ);
- }
- static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ);
- hci_conn_check_pending(hdev);
- }
- static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- BT_DBG("%s", hdev->name);
- }
- static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_role_discovery *rp = (void *) skb->data;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->role = rp->role;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = __le16_to_cpu(rp->policy);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_write_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = get_unaligned_le16(sent + 2);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->link_policy = __le16_to_cpu(rp->policy);
- }
- static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
- if (!sent)
- return;
- hdev->link_policy = get_unaligned_le16(sent);
- }
- static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- clear_bit(HCI_RESET, &hdev->flags);
- if (status)
- return;
- /* Reset all non-persistent flags */
- hci_dev_clear_volatile_flags(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hdev->inq_tx_power = HCI_TX_POWER_INVALID;
- hdev->adv_tx_power = HCI_TX_POWER_INVALID;
- memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
- hdev->adv_data_len = 0;
- memset(hdev->scan_rsp_data, 0, sizeof(hdev->scan_rsp_data));
- hdev->scan_rsp_data_len = 0;
- hdev->le_scan_type = LE_SCAN_PASSIVE;
- hdev->ssp_debug_mode = 0;
- hci_bdaddr_list_clear(&hdev->le_white_list);
- hci_bdaddr_list_clear(&hdev->le_resolv_list);
- }
- static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_stored_link_key *rp = (void *)skb->data;
- struct hci_cp_read_stored_link_key *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_READ_STORED_LINK_KEY);
- if (!sent)
- return;
- if (!rp->status && sent->read_all == 0x01) {
- hdev->stored_max_keys = rp->max_keys;
- hdev->stored_num_keys = rp->num_keys;
- }
- }
- static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_delete_stored_link_key *rp = (void *)skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (rp->num_keys <= hdev->stored_num_keys)
- hdev->stored_num_keys -= rp->num_keys;
- else
- hdev->stored_num_keys = 0;
- }
- static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_set_local_name_complete(hdev, sent, status);
- else if (!status)
- memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_local_name *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (hci_dev_test_flag(hdev, HCI_SETUP) ||
- hci_dev_test_flag(hdev, HCI_CONFIG))
- memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
- }
- static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (!status) {
- __u8 param = *((__u8 *) sent);
- if (param == AUTH_ENABLED)
- set_bit(HCI_AUTH, &hdev->flags);
- else
- clear_bit(HCI_AUTH, &hdev->flags);
- }
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_auth_enable_complete(hdev, status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- __u8 param;
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
- if (!sent)
- return;
- param = *((__u8 *) sent);
- if (param)
- set_bit(HCI_ENCRYPT, &hdev->flags);
- else
- clear_bit(HCI_ENCRYPT, &hdev->flags);
- }
- static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- __u8 param;
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
- if (!sent)
- return;
- param = *((__u8 *) sent);
- hci_dev_lock(hdev);
- if (status) {
- hdev->discov_timeout = 0;
- goto done;
- }
- if (param & SCAN_INQUIRY)
- set_bit(HCI_ISCAN, &hdev->flags);
- else
- clear_bit(HCI_ISCAN, &hdev->flags);
- if (param & SCAN_PAGE)
- set_bit(HCI_PSCAN, &hdev->flags);
- else
- clear_bit(HCI_PSCAN, &hdev->flags);
- done:
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- memcpy(hdev->dev_class, rp->dev_class, 3);
- BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
- hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
- }
- static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (status == 0)
- memcpy(hdev->dev_class, sent, 3);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_set_class_of_dev_complete(hdev, sent, status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_voice_setting *rp = (void *) skb->data;
- __u16 setting;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- setting = __le16_to_cpu(rp->voice_setting);
- if (hdev->voice_setting == setting)
- return;
- hdev->voice_setting = setting;
- BT_DBG("%s voice setting 0x%4.4x", hdev->name, setting);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
- }
- static void hci_cc_write_voice_setting(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- __u16 setting;
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
- if (!sent)
- return;
- setting = get_unaligned_le16(sent);
- if (hdev->voice_setting == setting)
- return;
- hdev->voice_setting = setting;
- BT_DBG("%s voice setting 0x%4.4x", hdev->name, setting);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
- }
- static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_num_supported_iac *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->num_iac = rp->num_iac;
- BT_DBG("%s num iac %d", hdev->name, hdev->num_iac);
- }
- static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- struct hci_cp_write_ssp_mode *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (!status) {
- if (sent->mode)
- hdev->features[1][0] |= LMP_HOST_SSP;
- else
- hdev->features[1][0] &= ~LMP_HOST_SSP;
- }
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_ssp_enable_complete(hdev, sent->mode, status);
- else if (!status) {
- if (sent->mode)
- hci_dev_set_flag(hdev, HCI_SSP_ENABLED);
- else
- hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
- {
- u8 status = *((u8 *) skb->data);
- struct hci_cp_write_sc_support *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (!status) {
- if (sent->support)
- hdev->features[1][0] |= LMP_HOST_SC;
- else
- hdev->features[1][0] &= ~LMP_HOST_SC;
- }
- if (!hci_dev_test_flag(hdev, HCI_MGMT) && !status) {
- if (sent->support)
- hci_dev_set_flag(hdev, HCI_SC_ENABLED);
- else
- hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_local_version *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (hci_dev_test_flag(hdev, HCI_SETUP) ||
- hci_dev_test_flag(hdev, HCI_CONFIG)) {
- hdev->hci_ver = rp->hci_ver;
- hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
- hdev->lmp_ver = rp->lmp_ver;
- hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
- hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
- }
- }
- static void hci_cc_read_local_commands(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_commands *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (hci_dev_test_flag(hdev, HCI_SETUP) ||
- hci_dev_test_flag(hdev, HCI_CONFIG))
- memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
- }
- static void hci_cc_read_auth_payload_timeout(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_auth_payload_to *rp = (void *)skb->data;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->auth_payload_timeout = __le16_to_cpu(rp->timeout);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_write_auth_payload_timeout(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_write_auth_payload_to *rp = (void *)skb->data;
- struct hci_conn *conn;
- void *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->auth_payload_timeout = get_unaligned_le16(sent + 2);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_local_features(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_features *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- memcpy(hdev->features, rp->features, 8);
- /* Adjust default settings according to features
- * supported by device. */
- if (hdev->features[0][0] & LMP_3SLOT)
- hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
- if (hdev->features[0][0] & LMP_5SLOT)
- hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
- if (hdev->features[0][1] & LMP_HV2) {
- hdev->pkt_type |= (HCI_HV2);
- hdev->esco_type |= (ESCO_HV2);
- }
- if (hdev->features[0][1] & LMP_HV3) {
- hdev->pkt_type |= (HCI_HV3);
- hdev->esco_type |= (ESCO_HV3);
- }
- if (lmp_esco_capable(hdev))
- hdev->esco_type |= (ESCO_EV3);
- if (hdev->features[0][4] & LMP_EV4)
- hdev->esco_type |= (ESCO_EV4);
- if (hdev->features[0][4] & LMP_EV5)
- hdev->esco_type |= (ESCO_EV5);
- if (hdev->features[0][5] & LMP_EDR_ESCO_2M)
- hdev->esco_type |= (ESCO_2EV3);
- if (hdev->features[0][5] & LMP_EDR_ESCO_3M)
- hdev->esco_type |= (ESCO_3EV3);
- if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
- hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
- }
- static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (hdev->max_page < rp->max_page)
- hdev->max_page = rp->max_page;
- if (rp->page < HCI_MAX_PAGES)
- memcpy(hdev->features[rp->page], rp->features, 8);
- }
- static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->flow_ctl_mode = rp->mode;
- }
- static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_buffer_size *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->acl_mtu = __le16_to_cpu(rp->acl_mtu);
- hdev->sco_mtu = rp->sco_mtu;
- hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
- hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
- if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
- hdev->sco_mtu = 64;
- hdev->sco_pkts = 8;
- }
- hdev->acl_cnt = hdev->acl_pkts;
- hdev->sco_cnt = hdev->sco_pkts;
- BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
- hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
- }
- static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_bd_addr *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (test_bit(HCI_INIT, &hdev->flags))
- bacpy(&hdev->bdaddr, &rp->bdaddr);
- if (hci_dev_test_flag(hdev, HCI_SETUP))
- bacpy(&hdev->setup_addr, &rp->bdaddr);
- }
- static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (test_bit(HCI_INIT, &hdev->flags)) {
- hdev->page_scan_interval = __le16_to_cpu(rp->interval);
- hdev->page_scan_window = __le16_to_cpu(rp->window);
- }
- }
- static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- u8 status = *((u8 *) skb->data);
- struct hci_cp_write_page_scan_activity *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
- if (!sent)
- return;
- hdev->page_scan_interval = __le16_to_cpu(sent->interval);
- hdev->page_scan_window = __le16_to_cpu(sent->window);
- }
- static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->page_scan_type = rp->type;
- }
- static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- u8 status = *((u8 *) skb->data);
- u8 *type;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
- if (type)
- hdev->page_scan_type = *type;
- }
- static void hci_cc_read_data_block_size(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_data_block_size *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
- hdev->block_len = __le16_to_cpu(rp->block_len);
- hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
- hdev->block_cnt = hdev->num_blocks;
- BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
- hdev->block_cnt, hdev->block_len);
- }
- static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_clock *rp = (void *) skb->data;
- struct hci_cp_read_clock *cp;
- struct hci_conn *conn;
- BT_DBG("%s", hdev->name);
- if (skb->len < sizeof(*rp))
- return;
- if (rp->status)
- return;
- hci_dev_lock(hdev);
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
- if (!cp)
- goto unlock;
- if (cp->which == 0x00) {
- hdev->clock = le32_to_cpu(rp->clock);
- goto unlock;
- }
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn) {
- conn->clock = le32_to_cpu(rp->clock);
- conn->clock_accuracy = le16_to_cpu(rp->accuracy);
- }
- unlock:
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->amp_status = rp->amp_status;
- hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
- hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
- hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
- hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
- hdev->amp_type = rp->amp_type;
- hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
- hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
- hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
- hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
- }
- static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->inq_tx_power = rp->tx_power;
- }
- static void hci_cc_read_def_err_data_reporting(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_def_err_data_reporting *rp = (void *)skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->err_data_reporting = rp->err_data_reporting;
- }
- static void hci_cc_write_def_err_data_reporting(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *)skb->data);
- struct hci_cp_write_def_err_data_reporting *cp;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING);
- if (!cp)
- return;
- hdev->err_data_reporting = cp->err_data_reporting;
- }
- static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_pin_code_reply *rp = (void *) skb->data;
- struct hci_cp_pin_code_reply *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
- if (rp->status)
- goto unlock;
- cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
- if (!cp)
- goto unlock;
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (conn)
- conn->pin_length = cp->pin_len;
- unlock:
- hci_dev_unlock(hdev);
- }
- static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
- rp->status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
- hdev->le_pkts = rp->le_max_pkt;
- hdev->le_cnt = hdev->le_pkts;
- BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
- }
- static void hci_cc_le_read_local_features(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_local_features *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- memcpy(hdev->le_features, rp->features, 8);
- }
- static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->adv_tx_power = rp->tx_power;
- }
- static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
- rp->status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
- 0, rp->status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_dev_lock(hdev);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- }
- static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- }
- static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- bdaddr_t *sent;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- bacpy(&hdev->random_addr, sent);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- struct hci_cp_le_set_default_phy *cp;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_DEFAULT_PHY);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- hdev->le_tx_def_phys = cp->tx_phys;
- hdev->le_rx_def_phys = cp->rx_phys;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- struct hci_cp_le_set_adv_set_rand_addr *cp;
- struct adv_info *adv_instance;
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_SET_RAND_ADDR);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- if (!hdev->cur_adv_instance) {
- /* Store in hdev for instance 0 (Set adv and Directed advs) */
- bacpy(&hdev->random_addr, &cp->bdaddr);
- } else {
- adv_instance = hci_find_adv_instance(hdev,
- hdev->cur_adv_instance);
- if (adv_instance)
- bacpy(&adv_instance->random_addr, &cp->bdaddr);
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
- {
- __u8 *sent, status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- /* If we're doing connection initiation as peripheral. Set a
- * timeout in case something goes wrong.
- */
- if (*sent) {
- struct hci_conn *conn;
- hci_dev_set_flag(hdev, HCI_LE_ADV);
- conn = hci_lookup_le_connect(hdev);
- if (conn)
- queue_delayed_work(hdev->workqueue,
- &conn->le_conn_timeout,
- conn->conn_timeout);
- } else {
- hci_dev_clear_flag(hdev, HCI_LE_ADV);
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_set_ext_adv_enable *cp;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- if (cp->enable) {
- struct hci_conn *conn;
- hci_dev_set_flag(hdev, HCI_LE_ADV);
- conn = hci_lookup_le_connect(hdev);
- if (conn)
- queue_delayed_work(hdev->workqueue,
- &conn->le_conn_timeout,
- conn->conn_timeout);
- } else {
- hci_dev_clear_flag(hdev, HCI_LE_ADV);
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_cp_le_set_scan_param *cp;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- hdev->le_scan_type = cp->type;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_ext_scan_param(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_set_ext_scan_params *cp;
- __u8 status = *((__u8 *) skb->data);
- struct hci_cp_le_scan_phy_params *phy_param;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS);
- if (!cp)
- return;
- phy_param = (void *)cp->data;
- hci_dev_lock(hdev);
- hdev->le_scan_type = phy_param->type;
- hci_dev_unlock(hdev);
- }
- static bool has_pending_adv_report(struct hci_dev *hdev)
- {
- struct discovery_state *d = &hdev->discovery;
- return bacmp(&d->last_adv_addr, BDADDR_ANY);
- }
- static void clear_pending_adv_report(struct hci_dev *hdev)
- {
- struct discovery_state *d = &hdev->discovery;
- bacpy(&d->last_adv_addr, BDADDR_ANY);
- d->last_adv_data_len = 0;
- }
- static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 bdaddr_type, s8 rssi, u32 flags,
- u8 *data, u8 len)
- {
- struct discovery_state *d = &hdev->discovery;
- bacpy(&d->last_adv_addr, bdaddr);
- d->last_adv_addr_type = bdaddr_type;
- d->last_adv_rssi = rssi;
- d->last_adv_flags = flags;
- memcpy(d->last_adv_data, data, len);
- d->last_adv_data_len = len;
- }
- static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
- {
- hci_dev_lock(hdev);
- switch (enable) {
- case LE_SCAN_ENABLE:
- hci_dev_set_flag(hdev, HCI_LE_SCAN);
- if (hdev->le_scan_type == LE_SCAN_ACTIVE)
- clear_pending_adv_report(hdev);
- break;
- case LE_SCAN_DISABLE:
- /* We do this here instead of when setting DISCOVERY_STOPPED
- * since the latter would potentially require waiting for
- * inquiry to stop too.
- */
- if (has_pending_adv_report(hdev)) {
- struct discovery_state *d = &hdev->discovery;
- mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
- d->last_adv_addr_type, NULL,
- d->last_adv_rssi, d->last_adv_flags,
- d->last_adv_data,
- d->last_adv_data_len, NULL, 0);
- }
- /* Cancel this timer so that we don't try to disable scanning
- * when it's already disabled.
- */
- cancel_delayed_work(&hdev->le_scan_disable);
- hci_dev_clear_flag(hdev, HCI_LE_SCAN);
- /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
- * interrupted scanning due to a connect request. Mark
- * therefore discovery as stopped. If this was not
- * because of a connect request advertising might have
- * been disabled because of active scanning, so
- * re-enable it again if necessary.
- */
- if (hci_dev_test_and_clear_flag(hdev, HCI_LE_SCAN_INTERRUPTED))
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- else if (!hci_dev_test_flag(hdev, HCI_LE_ADV) &&
- hdev->discovery.state == DISCOVERY_FINDING)
- hci_req_reenable_advertising(hdev);
- break;
- default:
- bt_dev_err(hdev, "use of reserved LE_Scan_Enable param %d",
- enable);
- break;
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_set_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
- if (!cp)
- return;
- le_set_scan_enable_complete(hdev, cp->enable);
- }
- static void hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_set_ext_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE);
- if (!cp)
- return;
- le_set_scan_enable_complete(hdev, cp->enable);
- }
- static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_num_supported_adv_sets *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x No of Adv sets %u", hdev->name, rp->status,
- rp->num_of_sets);
- if (rp->status)
- return;
- hdev->le_num_of_adv_sets = rp->num_of_sets;
- }
- static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_white_list_size *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);
- if (rp->status)
- return;
- hdev->le_white_list_size = rp->size;
- }
- static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- hci_bdaddr_list_clear(&hdev->le_white_list);
- }
- static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_add_to_white_list *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
- if (!sent)
- return;
- hci_bdaddr_list_add(&hdev->le_white_list, &sent->bdaddr,
- sent->bdaddr_type);
- }
- static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_del_from_white_list *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
- if (!sent)
- return;
- hci_bdaddr_list_del(&hdev->le_white_list, &sent->bdaddr,
- sent->bdaddr_type);
- }
- static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_supported_states *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- memcpy(hdev->le_states, rp->le_states, 8);
- }
- static void hci_cc_le_read_def_data_len(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_def_data_len *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->le_def_tx_len = le16_to_cpu(rp->tx_len);
- hdev->le_def_tx_time = le16_to_cpu(rp->tx_time);
- }
- static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_write_def_data_len *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN);
- if (!sent)
- return;
- hdev->le_def_tx_len = le16_to_cpu(sent->tx_len);
- hdev->le_def_tx_time = le16_to_cpu(sent->tx_time);
- }
- static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_add_to_resolv_list *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST);
- if (!sent)
- return;
- hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
- sent->bdaddr_type, sent->peer_irk,
- sent->local_irk);
- }
- static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_le_del_from_resolv_list *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST);
- if (!sent)
- return;
- hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
- sent->bdaddr_type);
- }
- static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- hci_bdaddr_list_clear(&hdev->le_resolv_list);
- }
- static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_resolv_list_size *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);
- if (rp->status)
- return;
- hdev->le_resolv_list_size = rp->size;
- }
- static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- __u8 *sent, status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (*sent)
- hci_dev_set_flag(hdev, HCI_LL_RPA_RESOLUTION);
- else
- hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_le_read_max_data_len(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_rp_le_read_max_data_len *rp = (void *) skb->data;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hdev->le_max_tx_len = le16_to_cpu(rp->tx_len);
- hdev->le_max_tx_time = le16_to_cpu(rp->tx_time);
- hdev->le_max_rx_len = le16_to_cpu(rp->rx_len);
- hdev->le_max_rx_time = le16_to_cpu(rp->rx_time);
- }
- static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
- struct sk_buff *skb)
- {
- struct hci_cp_write_le_host_supported *sent;
- __u8 status = *((__u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- if (sent->le) {
- hdev->features[1][0] |= LMP_HOST_LE;
- hci_dev_set_flag(hdev, HCI_LE_ENABLED);
- } else {
- hdev->features[1][0] &= ~LMP_HOST_LE;
- hci_dev_clear_flag(hdev, HCI_LE_ENABLED);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING);
- }
- if (sent->simul)
- hdev->features[1][0] |= LMP_HOST_LE_BREDR;
- else
- hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_cp_le_set_adv_param *cp;
- u8 status = *((u8 *) skb->data);
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- hdev->adv_addr_type = cp->own_address_type;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_le_set_ext_adv_params *rp = (void *) skb->data;
- struct hci_cp_le_set_ext_adv_params *cp;
- struct adv_info *adv_instance;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- hdev->adv_addr_type = cp->own_addr_type;
- if (!hdev->cur_adv_instance) {
- /* Store in hdev for instance 0 */
- hdev->adv_tx_power = rp->tx_power;
- } else {
- adv_instance = hci_find_adv_instance(hdev,
- hdev->cur_adv_instance);
- if (adv_instance)
- adv_instance->tx_power = rp->tx_power;
- }
- /* Update adv data as tx power is known now */
- hci_req_update_adv_data(hdev, hdev->cur_adv_instance);
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_rp_read_rssi *rp = (void *) skb->data;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->rssi = rp->rssi;
- hci_dev_unlock(hdev);
- }
- static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
- {
- struct hci_cp_read_tx_power *sent;
- struct hci_rp_read_tx_power *rp = (void *) skb->data;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
- sent = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
- if (!sent)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (!conn)
- goto unlock;
- switch (sent->type) {
- case 0x00:
- conn->tx_power = rp->tx_power;
- break;
- case 0x01:
- conn->max_tx_power = rp->tx_power;
- break;
- }
- unlock:
- hci_dev_unlock(hdev);
- }
- static void hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, struct sk_buff *skb)
- {
- u8 status = *((u8 *) skb->data);
- u8 *mode;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status)
- return;
- mode = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE);
- if (mode)
- hdev->ssp_debug_mode = *mode;
- }
- static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
- {
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (status) {
- hci_conn_check_pending(hdev);
- return;
- }
- set_bit(HCI_INQUIRY, &hdev->flags);
- }
- static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_create_conn *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- BT_DBG("%s bdaddr %pMR hcon %p", hdev->name, &cp->bdaddr, conn);
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- if (status != 0x0c || conn->attempt > 2) {
- conn->state = BT_CLOSED;
- hci_connect_cfm(conn, status);
- hci_conn_del(conn);
- } else
- conn->state = BT_CONNECT2;
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr,
- HCI_ROLE_MASTER);
- if (!conn)
- bt_dev_err(hdev, "no memory for new connection");
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_add_sco *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
- if (!cp)
- return;
- handle = __le16_to_cpu(cp->handle);
- BT_DBG("%s handle 0x%4.4x", hdev->name, handle);
- hci_dev_lock(hdev);
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
- hci_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_auth_requested *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_AUTH_REQUESTED);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_connect_cfm(conn, status);
- hci_conn_drop(conn);
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_set_conn_encrypt *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_SET_CONN_ENCRYPT);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_connect_cfm(conn, status);
- hci_conn_drop(conn);
- }
- }
- hci_dev_unlock(hdev);
- }
- static int hci_outgoing_auth_needed(struct hci_dev *hdev,
- struct hci_conn *conn)
- {
- if (conn->state != BT_CONFIG || !conn->out)
- return 0;
- if (conn->pending_sec_level == BT_SECURITY_SDP)
- return 0;
- /* Only request authentication for SSP connections or non-SSP
- * devices with sec_level MEDIUM or HIGH or if MITM protection
- * is requested.
- */
- if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
- conn->pending_sec_level != BT_SECURITY_FIPS &&
- conn->pending_sec_level != BT_SECURITY_HIGH &&
- conn->pending_sec_level != BT_SECURITY_MEDIUM)
- return 0;
- return 1;
- }
- static int hci_resolve_name(struct hci_dev *hdev,
- struct inquiry_entry *e)
- {
- struct hci_cp_remote_name_req cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- cp.pscan_rep_mode = e->data.pscan_rep_mode;
- cp.pscan_mode = e->data.pscan_mode;
- cp.clock_offset = e->data.clock_offset;
- return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
- }
- static bool hci_resolve_next_name(struct hci_dev *hdev)
- {
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
- if (list_empty(&discov->resolve))
- return false;
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
- if (!e)
- return false;
- if (hci_resolve_name(hdev, e) == 0) {
- e->name_state = NAME_PENDING;
- return true;
- }
- return false;
- }
- static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
- bdaddr_t *bdaddr, u8 *name, u8 name_len)
- {
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
- /* Update the mgmt connected state if necessary. Be careful with
- * conn objects that exist but are not (yet) connected however.
- * Only those in BT_CONFIG or BT_CONNECTED states can be
- * considered connected.
- */
- if (conn &&
- (conn->state == BT_CONFIG || conn->state == BT_CONNECTED) &&
- !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, conn, 0, name, name_len);
- if (discov->state == DISCOVERY_STOPPED)
- return;
- if (discov->state == DISCOVERY_STOPPING)
- goto discov_complete;
- if (discov->state != DISCOVERY_RESOLVING)
- return;
- e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
- /* If the device was not found in a list of found devices names of which
- * are pending. there is no need to continue resolving a next name as it
- * will be done upon receiving another Remote Name Request Complete
- * Event */
- if (!e)
- return;
- list_del(&e->list);
- if (name) {
- e->name_state = NAME_KNOWN;
- mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
- e->data.rssi, name, name_len);
- } else {
- e->name_state = NAME_NOT_KNOWN;
- }
- if (hci_resolve_next_name(hdev))
- return;
- discov_complete:
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- }
- static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_remote_name_req *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- /* If successful wait for the name req complete event before
- * checking for the need to do authentication */
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_REMOTE_NAME_REQ);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (hci_dev_test_flag(hdev, HCI_MGMT))
- hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0);
- if (!conn)
- goto unlock;
- if (!hci_outgoing_auth_needed(hdev, conn))
- goto unlock;
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested auth_cp;
- set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags);
- auth_cp.handle = __cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
- sizeof(auth_cp), &auth_cp);
- }
- unlock:
- hci_dev_unlock(hdev);
- }
- static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_read_remote_features *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_FEATURES);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_connect_cfm(conn, status);
- hci_conn_drop(conn);
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_read_remote_ext_features *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_connect_cfm(conn, status);
- hci_conn_drop(conn);
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_setup_sync_conn *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
- if (!cp)
- return;
- handle = __le16_to_cpu(cp->handle);
- BT_DBG("%s handle 0x%4.4x", hdev->name, handle);
- hci_dev_lock(hdev);
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
- hci_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
- hci_dev_unlock(hdev);
- }
- static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
- {
- struct hci_cp_sniff_mode *cp;
- struct hci_conn *conn;
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
- if (!status)
- return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
- if (!cp)
- return;
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(c…