/* Command Status OGF LINK_POLICY */ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) { BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { case OCF_SNIFF_MODE: if (status) { struct hci_conn *conn; struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE); if (!cp) break; 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->pend); } hci_dev_unlock(hdev); } break; case OCF_EXIT_SNIFF_MODE: if (status) { struct hci_conn *conn; struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE); if (!cp) break; 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->pend); } hci_dev_unlock(hdev); } break; default: BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf); break; } }
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%x", 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 %d", hdev->name, handle); hci_dev_lock(hdev); acl = hci_conn_hash_lookup_handle(hdev, handle); if (acl && (sco = acl->link)) { sco->state = BT_CLOSED; clear_bit(HCI_CONN_SCO_PEND, &sco->pend); hci_proto_connect_cfm(sco, status); hci_conn_del(sco); } hci_dev_unlock(hdev); }
static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) { struct hci_cp_exit_sniff_mode *cp; struct hci_conn *conn; BT_DBG("%s status 0x%x", hdev->name, status); if (!status) return; cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_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->pend); if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) hci_sco_setup(conn, status); } 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%x", 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 %d", hdev->name, handle); hci_dev_lock(hdev); acl = hci_conn_hash_lookup_handle(hdev, handle); if (acl && (sco = acl->link)) { sco->state = BT_CLOSED; hci_proto_connect_cfm(sco, status); hci_conn_del(sco); } hci_dev_unlock(hdev); }
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%x", 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 (conn && hci_outgoing_auth_needed(hdev, conn)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } hci_dev_unlock(hdev); }
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%x", 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%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_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) { struct hci_cp_exit_sniff_mode *cp; struct hci_conn *conn; struct hci_conn *sco; BT_DBG("%s status 0x%x", hdev->name, status); if (!status) return; cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_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->pend); sco = conn->link; if (sco) { if (test_and_clear_bit(HCI_CONN_SCO_PEND, &sco->pend)) { hci_proto_connect_cfm(sco, status); hci_conn_del(sco); } } } hci_dev_unlock(hdev); }
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_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%x", 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_proto_connect_cfm(conn, status); hci_conn_put(conn); } } 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%x", 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_proto_connect_cfm(conn, status); hci_conn_put(conn); } } hci_dev_unlock(hdev); }
/* Command Status OGF LINK_CTL */ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) { struct hci_conn *conn; struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); if (!cp) return; hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, status, batostr(&cp->bdaddr), conn); if (status) { if (conn && conn->state == BT_CONNECT) { conn->state = BT_CLOSED; hci_proto_connect_cfm(conn, status); hci_conn_del(conn); } } 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_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%x", 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_proto_connect_cfm(conn, status); hci_conn_put(conn); } } hci_dev_unlock(hdev); }
/* Command Complete OGF LINK_POLICY */ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) { struct hci_conn *conn; struct hci_rp_role_discovery *rd; struct hci_rp_write_link_policy *lp; void *sent; BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { case OCF_ROLE_DISCOVERY: rd = (void *) skb->data; if (rd->status) break; hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); if (conn) { if (rd->role) conn->link_mode &= ~HCI_LM_MASTER; else conn->link_mode |= HCI_LM_MASTER; } hci_dev_unlock(hdev); break; case OCF_WRITE_LINK_POLICY: sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY); if (!sent) break; lp = (struct hci_rp_write_link_policy *) skb->data; if (lp->status) break; hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle)); if (conn) { __le16 policy = get_unaligned((__le16 *) (sent + 2)); conn->link_policy = __le16_to_cpu(policy); } hci_dev_unlock(hdev); break; default: BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); break; } }
static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) { BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { case OCF_CREATE_CONN: hci_cs_create_conn(hdev, status); break; case OCF_ADD_SCO: if (status) { struct hci_conn *acl, *sco; struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO); __u16 handle; if (!cp) break; handle = __le16_to_cpu(cp->handle); BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); hci_dev_lock(hdev); acl = hci_conn_hash_lookup_handle(hdev, handle); if (acl && (sco = acl->link)) { sco->state = BT_CLOSED; hci_proto_connect_cfm(sco, status); hci_conn_del(sco); } hci_dev_unlock(hdev); } break; case OCF_INQUIRY: if (status) { BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status); hci_req_complete(hdev, status); } else { set_bit(HCI_INQUIRY, &hdev->flags); } break; default: BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", hdev->name, ocf, status); break; } }
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); if (status) return; sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) return; memcpy(hdev->dev_class, sent, 3); }
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%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); if (!sent) return; if (!status) hdev->link_policy = get_unaligned_le16(sent); hci_req_complete(hdev, status); }
static void hci_cc_write_ssp_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); if (status) return; sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) return; hdev->ssp_mode = *((__u8 *) sent); }
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); if (status) return; sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; memcpy(hdev->dev_name, sent, 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_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) conn->link_policy = get_unaligned_le16(sent + 2); hci_dev_unlock(hdev); }
/* Command Complete OGF HOST_CTL */ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) { __u8 status, param; void *sent; BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { case OCF_RESET: status = *((__u8 *) skb->data); hci_req_complete(hdev, status); break; case OCF_SET_EVENT_FLT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); } else { BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); } break; case OCF_WRITE_AUTH_ENABLE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); if (!status) { if (param == AUTH_ENABLED) set_bit(HCI_AUTH, &hdev->flags); else clear_bit(HCI_AUTH, &hdev->flags); } hci_req_complete(hdev, status); break; case OCF_WRITE_ENCRYPT_MODE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); if (!status) { if (param) set_bit(HCI_ENCRYPT, &hdev->flags); else clear_bit(HCI_ENCRYPT, &hdev->flags); } hci_req_complete(hdev, status); break; case OCF_WRITE_CA_TIMEOUT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); } else { BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); } break; case OCF_WRITE_PG_TIMEOUT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); } else { BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); } break; case OCF_WRITE_SCAN_ENABLE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); BT_DBG("param 0x%x", param); if (!status) { 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); break; case OCF_HOST_BUFFER_SIZE: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); hci_req_complete(hdev, status); } break; default: BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); break; }; }
/* Command Complete OGF HOST_CTL */ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) { __u8 status, param; __u16 setting; struct hci_rp_read_voice_setting *vs; void *sent; BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { case OCF_RESET: status = *((__u8 *) skb->data); hci_req_complete(hdev, status); break; case OCF_SET_EVENT_FLT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); } else { BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); } break; case OCF_WRITE_AUTH_ENABLE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); if (!status) { if (param == AUTH_ENABLED) set_bit(HCI_AUTH, &hdev->flags); else clear_bit(HCI_AUTH, &hdev->flags); } hci_req_complete(hdev, status); break; case OCF_WRITE_ENCRYPT_MODE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); if (!status) { if (param) set_bit(HCI_ENCRYPT, &hdev->flags); else clear_bit(HCI_ENCRYPT, &hdev->flags); } hci_req_complete(hdev, status); break; case OCF_WRITE_CA_TIMEOUT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); } else { BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); } break; case OCF_WRITE_PG_TIMEOUT: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); } else { BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); } break; case OCF_WRITE_SCAN_ENABLE: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); if (!sent) break; status = *((__u8 *) skb->data); param = *((__u8 *) sent); BT_DBG("param 0x%x", param); if (!status) { 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); break; case OCF_READ_VOICE_SETTING: vs = (struct hci_rp_read_voice_setting *) skb->data; if (vs->status) { BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status); break; } setting = __le16_to_cpu(vs->voice_setting); 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); } } break; case OCF_WRITE_VOICE_SETTING: sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING); if (!sent) break; status = *((__u8 *) skb->data); setting = __le16_to_cpu(get_unaligned((__le16 *) sent)); if (!status && 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); } } hci_req_complete(hdev, status); break; case OCF_HOST_BUFFER_SIZE: status = *((__u8 *) skb->data); if (status) { BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); hci_req_complete(hdev, status); } break; default: BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); break; } }