static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_cmd_pairing *paircmd = (void *) &conn->prsp[1]; struct link_key *key; struct key_master_id *id; u8 keydist = paircmd->init_key_dist; skb_pull(skb, sizeof(*rp)); key = hci_find_link_key_type(conn->hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key == NULL) return SMP_UNSPECIFIED; BT_DBG("keydist 0x%x", keydist); id = (void *) key->data; id->ediv = rp->ediv; memcpy(id->rand, rp->rand, sizeof(rp->rand)); hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size, rp->ediv, rp->rand, key->val); smp_distribute_keys(conn, 1); return 0; }
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_cmd_pairing *paircmd = (void *) &hcon->prsp[1]; struct link_key *key; u8 *keydist; skb_pull(skb, sizeof(*rp)); key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key == NULL) return SMP_UNSPECIFIED; if (hcon->out) keydist = &paircmd->resp_key_dist; else keydist = &paircmd->init_key_dist; BT_DBG("keydist 0x%x", *keydist); hci_add_ltk(hcon->hdev, 1, conn->dst, hcon->dst_type, hcon->smp_key_size, hcon->auth, rp->ediv, rp->rand, key->val); *keydist &= ~SMP_DIST_ENC_KEY; if (hcon->out) { if (!(*keydist)) smp_distribute_keys(conn, 1); } 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; }
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; }
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; }
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_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; }
static u8 smp_ltk_encrypt(struct l2cap_conn *conn) { struct link_key *key; struct key_master_id *master; struct hci_conn *hcon = conn->hcon; key = hci_find_link_key_type(hcon->hdev, conn->dst, HCI_LK_SMP_LTK); if (!key) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 1; master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; return 1; }
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; }