static int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing *req, *rsp; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); if (IS_ERR(hcon->hdev->tfm)) return PTR_ERR(hcon->hdev->tfm); rsp = (void *) &hcon->prsp[1]; /* The responder sends its keys first */ if (!force && hcon->out && (rsp->resp_key_dist & 0x07)) return 0; req = (void *) &hcon->preq[1]; if (hcon->out) { keydist = &rsp->init_key_dist; *keydist &= req->init_key_dist; } else { keydist = &rsp->resp_key_dist; *keydist &= req->resp_key_dist; } BT_DBG("keydist 0x%x", *keydist); if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; __le16 ediv; get_random_bytes(enc.ltk, sizeof(enc.ltk)); get_random_bytes(&ediv, sizeof(ediv)); get_random_bytes(ident.rand, sizeof(ident.rand)); smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); hci_add_ltk(hcon->hdev, 1, conn->dst, hcon->dst_type, hcon->smp_key_size, hcon->auth, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); *keydist &= ~SMP_DIST_ENC_KEY; } if (*keydist & SMP_DIST_ID_KEY) { struct smp_cmd_ident_addr_info addrinfo; struct smp_cmd_ident_info idinfo; /* Send a dummy key */ get_random_bytes(idinfo.irk, sizeof(idinfo.irk)); smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); /* Just public address */ memset(&addrinfo, 0, sizeof(addrinfo)); bacpy(&addrinfo.bdaddr, conn->src); smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), &addrinfo); *keydist &= ~SMP_DIST_ID_KEY; } if (*keydist & SMP_DIST_SIGN) { struct smp_cmd_sign_info sign; /* Send a dummy key */ get_random_bytes(sign.csrk, sizeof(sign.csrk)); smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); *keydist &= ~SMP_DIST_SIGN; } if (hcon->out) { if (hcon->disconn_cfm_cb) hcon->disconn_cfm_cb(hcon, 0); del_timer(&hcon->smp_timer); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ hci_conn_put(hcon); } else if (rsp->resp_key_dist) { if (hcon->disconn_cfm_cb) hcon->disconn_cfm_cb(hcon, SMP_UNSPECIFIED); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ mgmt_auth_failed(hcon->hdev->id, conn->dst, SMP_UNSPECIFIED); hci_conn_put(hcon); } return 0; }
/* Connect Complete */ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; struct hci_conn *conn, *pend; BT_DBG("%s", hdev->name); hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { hci_dev_unlock(hdev); return; } if (!ev->status) { conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; if (test_bit(HCI_AUTH, &hdev->flags)) conn->link_mode |= HCI_LM_AUTH; if (test_bit(HCI_ENCRYPT, &hdev->flags)) conn->link_mode |= HCI_LM_ENCRYPT; /* Get remote features */ if (conn->type == ACL_LINK) { struct hci_cp_read_remote_features cp; cp.handle = ev->handle; hci_send_cmd(hdev, OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp); } /* Set link policy */ if (conn->type == ACL_LINK && hdev->link_policy) { struct hci_cp_write_link_policy cp; cp.handle = ev->handle; cp.policy = __cpu_to_le16(hdev->link_policy); hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); } /* Set packet type for incoming connection */ if (!conn->out) { struct hci_cp_change_conn_ptype cp; cp.handle = ev->handle; cp.pkt_type = (conn->type == ACL_LINK) ? __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); } else { /* Update disconnect timer */ hci_conn_hold(conn); hci_conn_put(conn); } } else conn->state = BT_CLOSED; if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) { if (!ev->status) hci_add_sco(sco, conn->handle); else { hci_proto_connect_cfm(sco, ev->status); hci_conn_del(sco); } } } hci_proto_connect_cfm(conn, ev->status); if (ev->status) hci_conn_del(conn); pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); if (pend) hci_acl_connect(pend); hci_dev_unlock(hdev); }
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; __u8 code = skb->data[0]; __u8 reason; int err = 0; if (IS_ERR(hcon->hdev->tfm)) { err = PTR_ERR(hcon->hdev->tfm); reason = SMP_PAIRING_NOTSUPP; BT_ERR("SMP_PAIRING_NOTSUPP %p", hcon->hdev->tfm); goto done; } hcon->smp_conn = conn; skb_pull(skb, sizeof(code)); switch (code) { case SMP_CMD_PAIRING_REQ: reason = smp_cmd_pairing_req(conn, skb); break; case SMP_CMD_PAIRING_FAIL: reason = 0; err = -EPERM; del_timer(&hcon->smp_timer); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ mgmt_auth_failed(hcon->hdev->id, conn->dst, skb->data[0]); hci_conn_put(hcon); break; case SMP_CMD_PAIRING_RSP: reason = smp_cmd_pairing_rsp(conn, skb); break; case SMP_CMD_SECURITY_REQ: reason = smp_cmd_security_req(conn, skb); break; case SMP_CMD_PAIRING_CONFIRM: reason = smp_cmd_pairing_confirm(conn, skb); break; case SMP_CMD_PAIRING_RANDOM: reason = smp_cmd_pairing_random(conn, skb); break; case SMP_CMD_ENCRYPT_INFO: reason = smp_cmd_encrypt_info(conn, skb); break; case SMP_CMD_MASTER_IDENT: reason = smp_cmd_master_ident(conn, skb); break; case SMP_CMD_IDENT_INFO: case SMP_CMD_IDENT_ADDR_INFO: case SMP_CMD_SIGN_INFO: /* Just ignored */ reason = 0; break; default: BT_DBG("Unknown command code 0x%2.2x", code); reason = SMP_CMD_NOTSUPP; err = -EOPNOTSUPP; goto done; } done: if (reason) { BT_ERR("SMP_CMD_PAIRING_FAIL: %d", reason); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); del_timer(&hcon->smp_timer); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ mgmt_auth_failed(hcon->hdev->id, conn->dst, reason); hci_conn_put(hcon); } kfree_skb(skb); return err; }
void smp_chan_destroy(struct l2cap_conn *conn) { kfree(conn->smp_chan); hci_conn_put(conn->hcon); }
static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_remote_features *ev = (void *) skb->data; struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) memcpy(conn->features, ev->features, 8); if (conn->state == BT_CONFIG) { if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) { struct hci_cp_read_remote_ext_features cp; cp.handle = ev->handle; cp.page = 0x01; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES, sizeof(cp), &cp); } else { if (!(conn->features[3]&(0x02|0x04))) /* not support 2M/3M EDR. 0x02=2M 0x04=3M */ { if (!(conn->link_mode & HCI_LM_MASTER)) /* act as slave */ { if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) { struct hci_cp_switch_role cp; cp.bdaddr.b[0]= 0; /* init */ cp.bdaddr.b[1]= 0; cp.bdaddr.b[2]= 0; cp.bdaddr.b[3]= 0; cp.bdaddr.b[4]= 0; cp.bdaddr.b[5]= 0; cp.role = 0; bacpy(&cp.bdaddr, &conn->dst); /* switch to master */ cp.role = 0x0; BT_DBG("switch to master"); hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp); } } else { struct hci_cp_write_link_policy cp; cp.handle = 0; /* init */ cp.policy = 0; /* disable role_switch if already act as master */ cp.handle = cpu_to_le16(conn->handle); conn->link_policy |= HCI_LP_SNIFF; conn->link_policy |= HCI_LP_HOLD; conn->link_policy &= ~HCI_LP_RSWITCH; cp.policy = cpu_to_le16(conn->link_policy); hci_send_cmd(conn->hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp); } } conn->state = BT_CONNECTED; hci_proto_connect_cfm(conn, ev->status); hci_conn_put(conn); } } } hci_dev_unlock(hdev); }
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_auth_complete *ev = (void *) skb->data; struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_AUTH; else conn->sec_level = BT_SECURITY_LOW; //modify the problem of PIN or KEY MISSIMG ZTE_BT_QXX_20101118 begin if (ev->status == 0x06 && hdev->ssp_mode > 0 && conn->ssp_mode > 0 && conn->out) { // PIN or KEY MISSING struct hci_cp_auth_requested cp; cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); goto done; } //modify the problem of PIN or KEY MISSIMG ZTE_BT_QXX_20101118 end clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); if (conn->state == BT_CONFIG) { if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { conn->state = BT_CONNECTED; hci_proto_connect_cfm(conn, ev->status); hci_conn_put(conn); } } else { hci_auth_cfm(conn, ev->status); hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; hci_conn_put(conn); } if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); } } } //modify the problem of PIN or KEY MISSIMG ZTE_BT_QXX_20101118 done: hci_dev_unlock(hdev); }
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_auth_complete *ev = (void *) skb->data; struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_AUTH; else conn->sec_level = BT_SECURITY_LOW; // BEGIN SS_BLUEZ_BT +kjh 2011.03.17 : // workaround for nobonding. // cond 1. local has link key. remote doesn't have link key. // cond 2. local & remote are ssp mode // cond 3. send opp file from local to remote // result -> pin or key missing err returned. // so send "HCI_OP_AUTH_REQUESTED" one more time. if (ev->status == 0x06 && hdev->ssp_mode > 0 && // 0x06 Error code (PIN or key missing) conn->ssp_mode > 0 && conn->out) { // hdev: remote device, conn: connection struct hci_cp_auth_requested cp; cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); printk(KERN_ERR "error code = 0x06, sspmode => HCI_OP_AUTH_REQUESTED"); goto done; } // END SS_BLUEZ_BT clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); if (conn->state == BT_CONFIG) { if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { conn->state = BT_CONNECTED; hci_proto_connect_cfm(conn, ev->status); hci_conn_put(conn); } } else { hci_auth_cfm(conn, ev->status); hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; hci_conn_put(conn); } if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); } } } // BEGIN SS_BLUEZ_BT +kjh 2011.03.17 : done: // END SS_BLUEZ_BT hci_dev_unlock(hdev); }