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 (skb->len < sizeof(*req)) return SMP_UNSPECIFIED; 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; get_random_bytes(smp->prnd, sizeof(smp->prnd)); 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; clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags); 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 (skb->len < sizeof(*rsp)) return SMP_UNSPECIFIED; 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; get_random_bytes(smp->prnd, sizeof(smp->prnd)); smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); /* Update remote key distribution in case the remote cleared * some bits that we had enabled in our request. */ smp->remote_key_dist &= rsp->resp_key_dist; 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)) 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; }