static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; u8 key_size; int ret; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); req = (void *) &smp->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; if (rsp->oob_flag) return SMP_OOB_NOT_AVAIL; /* Just works */ memset(smp->tk, 0, sizeof(smp->tk)); ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); queue_work(hdev->workqueue, &smp->confirm); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_chan *smp; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp = smp_chan_create(conn); else smp = conn->smp_chan; if (!smp) return SMP_UNSPECIFIED; smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); /* We didn't start the pairing, so match remote */ if (req->auth_req & SMP_AUTH_BONDING) auth = req->auth_req; conn->hcon->pending_sec_level = authreq_to_seclevel(auth); build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); /* Request setup of TK */ ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; return 0; }
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; u8 key_size, auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; skb_pull(skb, sizeof(*rsp)); req = (void *) &smp->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); if ((req->auth_req & SMP_AUTH_BONDING) && (rsp->auth_req & SMP_AUTH_BONDING)) auth = SMP_AUTH_BONDING; auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM; ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability); if (ret) return SMP_UNSPECIFIED; set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); /* Can't compose response until we have been confirmed */ if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) return 0; queue_work(hdev->workqueue, &smp->confirm); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag && hcon->oob) { auth = req->auth_req | SMP_AUTH_MITM; } else if (req->auth_req & SMP_AUTH_BONDING) { auth = SMP_AUTH_BONDING | SMP_AUTH_MITM; } build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(hcon->prnd); if (ret) return SMP_UNSPECIFIED; ret = tk_request(conn, req->oob_flag, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; hcon->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&hcon->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag && hcon->oob) { /* By definition, OOB data pairing will have MITM protection */ auth = req->auth_req | SMP_AUTH_MITM; } else if (req->auth_req & SMP_AUTH_BONDING) { /* We will attempt MITM for all Bonding attempts */ auth = SMP_AUTH_BONDING | SMP_AUTH_MITM; } /* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(hcon->prnd); if (ret) return SMP_UNSPECIFIED; /* Request setup of TK */ ret = tk_request(conn, req->oob_flag, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; hcon->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&hcon->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing *req, *rsp = (void *) skb->data; u8 key_size, auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); req = (void *) &hcon->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; hcon->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&hcon->prsp[1], rsp, sizeof(*rsp)); ret = smp_rand(hcon->prnd); if (ret) return SMP_UNSPECIFIED; if ((req->auth_req & SMP_AUTH_BONDING) && (rsp->auth_req & SMP_AUTH_BONDING)) auth = SMP_AUTH_BONDING; auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM; ret = tk_request(conn, req->oob_flag, auth, rsp->io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; hcon->cfm_pending = TRUE; if (!hcon->tk_valid) return 0; ret = send_pairing_confirm(conn); if (ret) return SMP_CONFIRM_FAILED; return 0; }
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_cmd_pairing_confirm cp; struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; int ret; u8 res[16], key_size; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); req = (void *) &conn->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; if (rsp->oob_flag) return SMP_OOB_NOT_AVAIL; /* Just works */ memset(conn->tk, 0, sizeof(conn->tk)); conn->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&conn->prsp[1], rsp, sizeof(*rsp)); ret = smp_rand(conn->prnd); if (ret) return SMP_UNSPECIFIED; ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, conn->src, conn->hcon->dst_type, conn->dst, res); if (ret) return SMP_UNSPECIFIED; swap128(res, cp.confirm_val); smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_chan *smp; u8 key_size; int ret; BT_DBG("conn %p", conn); if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) smp = smp_chan_create(conn); smp = conn->smp_chan; smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag) return SMP_OOB_NOT_AVAIL; /* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; /* Just works */ memset(smp->tk, 0, sizeof(smp->tk)); ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); return 0; }
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf)); skb_pull(skb, sizeof(conn->pcnf)); if (conn->hcon->out) { u8 random[16]; swap128(conn->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); } else { struct smp_cmd_pairing_confirm cp; int ret; u8 res[16]; ret = smp_rand(conn->prnd); if (ret) return SMP_UNSPECIFIED; ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, conn->hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) return SMP_CONFIRM_FAILED; swap128(res, cp.confirm_val); smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); } mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }