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