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 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; }
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; }