📄 hci_event.c
字号:
/* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated 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 <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/interrupt.h>#include <linux/notifier.h>#include <net/sock.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h>#ifndef CONFIG_BT_HCI_CORE_DEBUG#undef BT_DBG#define BT_DBG(D...)#endif/* 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%x", hdev->name, status); if (status) return; clear_bit(HCI_INQUIRY, &hdev->flags); hci_req_complete(hdev, status); hci_conn_check_pending(hdev);}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%x", hdev->name, status); if (status) return; clear_bit(HCI_INQUIRY, &hdev->flags); 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%x", 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) { if (rp->role) conn->link_mode &= ~HCI_LM_MASTER; else conn->link_mode |= HCI_LM_MASTER; } 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%x", 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) { __le16 policy = get_unaligned((__le16 *) (sent + 2)); conn->link_policy = __le16_to_cpu(policy); } hci_dev_unlock(hdev);}static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb){ __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); hci_req_complete(hdev, status);}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%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; if (!status) memcpy(hdev->dev_name, sent, 248);}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%x", hdev->name, rp->status); if (rp->status) return; memcpy(hdev->dev_name, rp->name, 248);}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%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE); if (!sent) return; if (!status) { __u8 param = *((__u8 *) sent); if (param == AUTH_ENABLED) set_bit(HCI_AUTH, &hdev->flags); else clear_bit(HCI_AUTH, &hdev->flags); } hci_req_complete(hdev, status);}static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb){ __u8 status = *((__u8 *) skb->data); void *sent; BT_DBG("%s status 0x%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE); if (!sent) return; if (!status) { __u8 param = *((__u8 *) sent); if (param) set_bit(HCI_ENCRYPT, &hdev->flags); else clear_bit(HCI_ENCRYPT, &hdev->flags); } hci_req_complete(hdev, status);}static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb){ __u8 status = *((__u8 *) skb->data); void *sent; BT_DBG("%s status 0x%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE); if (!sent) return; if (!status) { __u8 param = *((__u8 *) sent); clear_bit(HCI_PSCAN, &hdev->flags); clear_bit(HCI_ISCAN, &hdev->flags); if (param & SCAN_INQUIRY) set_bit(HCI_ISCAN, &hdev->flags); if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); } hci_req_complete(hdev, status);}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%x", 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%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) return; if (!status) memcpy(hdev->dev_class, sent, 3);}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%x", 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%04x", hdev->name, setting); if (hdev->notify) { tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); tasklet_enable(&hdev->tx_task); }}static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb){ __u8 status = *((__u8 *) skb->data); void *sent; BT_DBG("%s status 0x%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING); if (!sent) return; if (!status) { __u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent)); if (hdev->voice_setting != setting) { hdev->voice_setting = setting; BT_DBG("%s voice setting 0x%04x", hdev->name, setting); if (hdev->notify) { tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); tasklet_enable(&hdev->tx_task); } } }}static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb){ __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); hci_req_complete(hdev, status);}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%x", hdev->name, rp->status); if (rp->status) return; hdev->hci_ver = rp->hci_ver; hdev->hci_rev = btohs(rp->hci_rev); hdev->manufacturer = btohs(rp->manufacturer); BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);}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%x", hdev->name, rp->status); if (rp->status) return; memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));}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%x", 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] & LMP_3SLOT) hdev->pkt_type |= (HCI_DM3 | HCI_DH3); if (hdev->features[0] & LMP_5SLOT) hdev->pkt_type |= (HCI_DM5 | HCI_DH5); if (hdev->features[1] & LMP_HV2) { hdev->pkt_type |= (HCI_HV2); hdev->esco_type |= (ESCO_HV2); } if (hdev->features[1] & LMP_HV3) { hdev->pkt_type |= (HCI_HV3); hdev->esco_type |= (ESCO_HV3); } if (hdev->features[3] & LMP_ESCO) hdev->esco_type |= (ESCO_EV3); if (hdev->features[4] & LMP_EV4) hdev->esco_type |= (ESCO_EV4); if (hdev->features[4] & LMP_EV5) hdev->esco_type |= (ESCO_EV5); BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name, hdev->features[0], hdev->features[1], hdev->features[2], hdev->features[3], hdev->features[4], hdev->features[5], hdev->features[6], hdev->features[7]);}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%x", 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%x", hdev->name, rp->status); if (!rp->status) bacpy(&hdev->bdaddr, &rp->bdaddr); hci_req_complete(hdev, rp->status);}static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status){ BT_DBG("%s status 0x%x", hdev->name, status); if (status) { hci_req_complete(hdev, status); hci_conn_check_pending(hdev); } else set_bit(HCI_INQUIRY, &hdev->flags);}static inline 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%x", 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 %s conn %p", hdev->name, batostr(&cp->bdaddr), conn); if (status) { if (conn && conn->state == BT_CONNECT) { if (status != 0x0c || conn->attempt > 2) { conn->state = BT_CLOSED; hci_proto_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); if (conn) { conn->out = 1; conn->link_mode |= HCI_LM_MASTER; } else BT_ERR("No memmory 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -