static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; BT_DBG("conn %p", conn); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->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(conn->tk, 0, sizeof(conn->tk)); conn->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&conn->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!lmp_host_le_capable(hcon->hdev)) return 1; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, HCI_LK_SMP_LTK); if (key) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); goto done; } build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; __u8 authreq; BT_DBG("conn %p hcon %p %d req: %d", conn, hcon, hcon->sec_level, sec_level); if (IS_ERR(hcon->hdev->tfm)) return 1; if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return -EINPROGRESS; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; authreq = seclevel_to_authreq(sec_level); hcon->smp_conn = conn; hcon->pending_sec_level = sec_level; if (hcon->link_mode & HCI_LM_MASTER) { struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (smp_encrypt_link(hcon, key) == 0) goto done; } hcon->sec_req = FALSE; if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); hci_conn_hold(hcon); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (IS_ERR(hcon->hdev->tfm)) return 1; if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return -EINPROGRESS; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level > sec_level) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; goto done; } } if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->preq[1], &cp, sizeof(cp)); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; struct smp_chan *smp; BT_DBG("conn %p", conn); hcon->pending_sec_level = BT_SECURITY_MEDIUM; if (smp_ltk_encrypt(conn)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) return 0; smp = smp_chan_create(conn); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); return 0; }
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; struct smp_chan *smp; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); /* This may be NULL if there's an unexpected disconnection */ if (!conn) return 1; if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) return 1; if (smp_sufficient_security(hcon, sec_level)) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn, sec_level)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return 1; authreq = seclevel_to_authreq(sec_level); /* Require MITM if IO Capability allows or the security level * requires it. */ if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT || sec_level > BT_SECURITY_MEDIUM) authreq |= SMP_AUTH_MITM; if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } set_bit(SMP_FLAG_INITIATOR, &smp->smp_flags); done: hcon->pending_sec_level = sec_level; 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 (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; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!lmp_host_le_capable(hcon->hdev)) return 1; /* SSBT :: KJH + (0223), for Pin or Key Missing case */ if (sec_level == BT_SECURITY_LOW) { if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn)) goto done; return 1; } if (hcon->sec_level >= sec_level) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct link_key *key; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key && ((key->auth & SMP_AUTH_MITM) || !(rp->auth_req & SMP_AUTH_MITM))) { if (smp_encrypt_link(hcon, key) < 0) goto invalid_key; hcon->sec_level = authreq_to_seclevel(key->auth); if (!(hcon->link_mode & HCI_LM_ENCRYPT)) hci_conn_hold(hcon); return 0; } invalid_key: hcon->sec_req = FALSE; /* Switch to Pairing Connection Parameters */ hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); hci_conn_hold(hcon); 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_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; }
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; struct smp_chan *smp = conn->smp_chan; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) return 1; if (smp_sufficient_security(hcon, sec_level)) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn, sec_level)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct link_key *key; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key && ((key->auth & SMP_AUTH_MITM) || !(rp->auth_req & SMP_AUTH_MITM))) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; hcon->sec_req = TRUE; hcon->sec_level = authreq_to_seclevel(rp->auth_req); return 0; } hcon->sec_req = FALSE; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!lmp_host_le_capable(hcon->hdev)) return 1; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) return 0; smp = smp_chan_create(conn); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = SMP_AUTH_NONE; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; 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_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; struct smp_chan *smp; u8 sec_level; BT_DBG("conn %p", conn); sec_level = authreq_to_seclevel(rp->auth_req); if (smp_sufficient_security(hcon, sec_level)) return 0; if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; struct smp_chan *smp; BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req); if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (IS_ERR(hcon->hdev->tfm)) { BT_DBG("IS_ERR"); return 1; } if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { BT_DBG("HCI_CONN_ENCRYPT_PEND"); return -EINPROGRESS; } if (sec_level == BT_SECURITY_LOW) { BT_DBG("BT_SECURITY_LOW"); return 1; } if (hcon->sec_level > sec_level) { BT_DBG("hcon->sec_level > sec_level"); return 1; } authreq = seclevel_to_authreq(sec_level); BT_ERR("conn = %p, sec: %d", conn, sec_level); hcon->smp_conn = conn; hcon->sec_level = sec_level; if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) { struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (smp_encrypt_link(hcon, key) == 0) goto done; } hcon->sec_req = FALSE; if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; /* Switch to Pairing Connection Parameters */ hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT); build_pairing_cmd(conn, &cp, NULL, authreq); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }