// SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2013-2014 Intel Corporation * * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "lib/bluetooth.h" #include "lib/hci.h" #include "src/shared/util.h" #include "src/shared/crypto.h" #include "src/shared/ecc.h" #include "monitor/bt.h" #include "bthost.h" #define SMP_CID 0x0006 #define SMP_BREDR_CID 0x0007 #define L2CAP_FC_SMP_BREDR 0x80 #define SMP_PASSKEY_ENTRY_FAILED 0x01 #define SMP_OOB_NOT_AVAIL 0x02 #define SMP_AUTH_REQUIREMENTS 0x03 #define SMP_CONFIRM_FAILED 0x04 #define SMP_PAIRING_NOTSUPP 0x05 #define SMP_ENC_KEY_SIZE 0x06 #define SMP_CMD_NOTSUPP 0x07 #define SMP_UNSPECIFIED 0x08 #define SMP_REPEATED_ATTEMPTS 0x09 #define SMP_INVALID_PARAMS 0x0a #define SMP_DHKEY_CHECK_FAILED 0x0b #define SMP_NUMERIC_COMP_FAILED 0x0c #define SMP_BREDR_PAIRING_IN_PROGRESS 0x0d #define DIST_ENC_KEY 0x01 #define DIST_ID_KEY 0x02 #define DIST_SIGN 0x04 #define DIST_LINK_KEY 0x08 #define SC_NO_DIST (DIST_ENC_KEY | DIST_LINK_KEY) #define MAX_IO_CAP 0x04 #define SMP_AUTH_NONE 0x00 #define SMP_AUTH_BONDING 0x01 #define SMP_AUTH_MITM 0x04 #define SMP_AUTH_SC 0x08 #define SMP_AUTH_KEYPRESS 0x10 struct smp { struct bthost *bthost; struct smp_conn *conn; struct bt_crypto *crypto; }; struct smp_conn { struct smp *smp; uint16_t handle; uint8_t addr_type; bool out; bool sc; bool initiator; uint8_t method; uint8_t local_key_dist; uint8_t remote_key_dist; uint8_t ia[6]; uint8_t ia_type; uint8_t ra[6]; uint8_t ra_type; uint8_t tk[16]; uint8_t prnd[16]; uint8_t rrnd[16]; uint8_t pcnf[16]; uint8_t preq[7]; uint8_t prsp[7]; uint8_t ltk[16]; uint8_t local_sk[32]; uint8_t local_pk[64]; uint8_t remote_pk[64]; uint8_t dhkey[32]; uint8_t mackey[16]; uint8_t passkey_notify; uint8_t passkey_round; }; enum { JUST_WORKS, JUST_CFM, REQ_PASSKEY, CFM_PASSKEY, REQ_OOB, DSP_PASSKEY, OVERLAP, }; static const uint8_t gen_method[5][5] = { { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM }, { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP }, }; static const uint8_t sc_method[5][5] = { { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, { JUST_WORKS, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, { DSP_PASSKEY, DSP_PASSKEY, REQ_PASSKEY, JUST_WORKS, DSP_PASSKEY }, { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM }, { DSP_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, }; static uint8_t get_auth_method(struct smp_conn *conn, uint8_t local_io, uint8_t remote_io) { /* If either side has unknown io_caps, use JUST_CFM (which gets * converted later to JUST_WORKS if we're initiators. */ if (local_io > MAX_IO_CAP || remote_io > MAX_IO_CAP) return JUST_CFM; if (conn->sc) return sc_method[remote_io][local_io]; return gen_method[remote_io][local_io]; } static uint8_t sc_select_method(struct smp_conn *conn) { struct bt_l2cap_smp_pairing_request *local, *remote; uint8_t local_mitm, remote_mitm, local_io, remote_io, method; if (conn->out) { local = (void *) &conn->preq[1]; remote = (void *) &conn->prsp[1]; } else { local = (void *) &conn->prsp[1]; remote = (void *) &conn->preq[1]; } local_io = local->io_capa; remote_io = remote->io_capa; local_mitm = (local->auth_req & SMP_AUTH_MITM); remote_mitm = (remote->auth_req & SMP_AUTH_MITM); /* If either side wants MITM, look up the method from the table, * otherwise use JUST WORKS. */ if (local_mitm || remote_mitm) method = get_auth_method(conn, local_io, remote_io); else method = JUST_WORKS; /* Don't confirm locally initiated pairing attempts */ if (method == JUST_CFM && conn->initiator) method = JUST_WORKS; return method; } static uint8_t key_dist(struct bthost *host) { if (!bthost_bredr_capable(host)) return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN); return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN | DIST_LINK_KEY); } static void smp_send(struct smp_conn *conn, uint8_t smp_cmd, const void *data, uint8_t len) { struct iovec iov[2]; uint16_t cid; iov[0].iov_base = &smp_cmd; iov[0].iov_len = 1; iov[1].iov_base = (void *) data; iov[1].iov_len = len; if (conn->addr_type == BDADDR_BREDR) cid = SMP_BREDR_CID; else cid = SMP_CID; bthost_send_cid_v(conn->smp->bthost, conn->handle, cid, iov, 2); } static bool send_public_key(struct smp_conn *conn) { if (!ecc_make_key(conn->local_pk, conn->local_sk)) return false; smp_send(conn, BT_L2CAP_SMP_PUBLIC_KEY, conn->local_pk, 64); return true; } static void sc_dhkey_check(struct smp_conn *conn) { uint8_t io_cap[3], r[16], a[7], b[7], *local_addr, *remote_addr; struct bt_l2cap_smp_dhkey_check check; memcpy(a, conn->ia, 6); memcpy(b, conn->ra, 6); a[6] = conn->ia_type; b[6] = conn->ra_type; if (conn->out) { local_addr = a; remote_addr = b; memcpy(io_cap, &conn->preq[1], 3); } else { local_addr = b; remote_addr = a; memcpy(io_cap, &conn->prsp[1], 3); } memset(r, 0, sizeof(r)); bt_crypto_f6(conn->smp->crypto, conn->mackey, conn->prnd, conn->rrnd, r, io_cap, local_addr, remote_addr, check.e); smp_send(conn, BT_L2CAP_SMP_DHKEY_CHECK, &check, sizeof(check)); } static void sc_mackey_and_ltk(struct smp_conn *conn) { uint8_t *na, *nb, a[7], b[7]; if (conn->out) { na = conn->prnd; nb = conn->rrnd; } else { na = conn->rrnd; nb = conn->prnd; } memcpy(a, conn->ia, 6); memcpy(b, conn->ra, 6); a[6] = conn->ia_type; b[6] = conn->ra_type; bt_crypto_f5(conn->smp->crypto, conn->dhkey, na, nb, a, b, conn->mackey, conn->ltk); } static uint8_t sc_passkey_send_confirm(struct smp_conn *conn) { struct bt_l2cap_smp_pairing_confirm cfm; uint8_t r; r = ((conn->passkey_notify >> conn->passkey_round) & 0x01); r |= 0x80; if (!bt_crypto_f4(conn->smp->crypto, conn->local_pk, conn->remote_pk, conn->prnd, r, cfm.value)) return SMP_UNSPECIFIED; smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, &cfm, sizeof(cfm)); return 0; } static uint8_t sc_passkey_round(struct smp_conn *conn, uint8_t smp_op) { uint8_t cfm[16], r; /* Ignore the PDU if we've already done 20 rounds (0 - 19) */ if (conn->passkey_round >= 20) return 0; switch (smp_op) { case BT_L2CAP_SMP_PAIRING_RANDOM: r = ((conn->passkey_notify >> conn->passkey_round) & 0x01); r |= 0x80; if (!bt_crypto_f4(conn->smp->crypto, conn->remote_pk, conn->local_pk, conn->rrnd, r, cfm)) return SMP_UNSPECIFIED; if (memcmp(conn->pcnf, cfm, 16)) return SMP_CONFIRM_FAILED; conn->passkey_round++; if (conn->passkey_round == 20) { /* Generate MacKey and LTK */ sc_mackey_and_ltk(conn); } /* The round is only complete when the initiator * receives pairing random. */ if (!conn->out) { smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, sizeof(conn->prnd)); return 0; } /* Start the next round */ if (conn->passkey_round != 20) return sc_passkey_round(conn, 0); /* Passkey rounds are complete - start DHKey Check */ sc_dhkey_check(conn); break; case BT_L2CAP_SMP_PAIRING_CONFIRM: if (conn->out) { smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, sizeof(conn->prnd)); return 0; } return sc_passkey_send_confirm(conn); case BT_L2CAP_SMP_PUBLIC_KEY: default: /* Initiating device starts the round */ if (!conn->out) return 0; return sc_passkey_send_confirm(conn); } return 0; } static bool verify_random(struct smp_conn *conn, const uint8_t rnd[16]) { uint8_t confirm[16]; if (!bt_crypto_c1(conn->smp->crypto, conn->tk, conn->rrnd, conn->prsp, conn->preq, conn->ia_type, conn->ia, conn->ra_type, conn->ra, confirm)) return false; if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { bthost_debug(conn->smp->bthost, "Confirmation values don't match"); return false; } if (conn->out) { bt_crypto_s1(conn->smp->crypto, conn->tk, conn->rrnd, conn->prnd, conn->ltk); bthost_le_start_encrypt(conn->smp->bthost, conn->handle, conn->ltk); } else { bt_crypto_s1(conn->smp->crypto, conn->tk, conn->prnd, conn->rrnd, conn->ltk); } return true; } static void distribute_keys(struct smp_conn *conn) { uint8_t buf[16]; if (conn->local_key_dist & DIST_ENC_KEY) { memset(buf, 0, sizeof(buf)); smp_send(conn, BT_L2CAP_SMP_ENCRYPT_INFO, buf, sizeof(buf)); smp_send(conn, BT_L2CAP_SMP_CENTRAL_IDENT, buf, 10); } if (conn->local_key_dist & DIST_ID_KEY) { memset(buf, 0, sizeof(buf)); smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf)); memset(buf, 0, sizeof(buf)); if (conn->out) { buf[0] = conn->ia_type; memcpy(&buf[1], conn->ia, 6); } else { buf[0] = conn->ra_type; memcpy(&buf[1], conn->ra, 6); } smp_send(conn, BT_L2CAP_SMP_IDENT_ADDR_INFO, buf, 7); } if (conn->local_key_dist & DIST_SIGN) { memset(buf, 0, sizeof(buf)); smp_send(conn, BT_L2CAP_SMP_SIGNING_INFO, buf, sizeof(buf)); } } static void pairing_req(struct smp_conn *conn, const void *data, uint16_t len) { struct bthost *bthost = conn->smp->bthost; struct bt_l2cap_smp_pairing_response rsp; memcpy(conn->preq, data, sizeof(conn->preq)); if (conn->addr_type == BDADDR_BREDR) { rsp.io_capa = 0x00; rsp.oob_data = 0x00; rsp.auth_req = 0x00; } else { rsp.io_capa = bthost_get_io_capability(bthost); rsp.oob_data = 0x00; rsp.auth_req = bthost_get_auth_req(bthost); } rsp.max_key_size = 0x10; rsp.init_key_dist = conn->preq[5] & key_dist(bthost); rsp.resp_key_dist = conn->preq[6] & key_dist(bthost); conn->prsp[0] = BT_L2CAP_SMP_PAIRING_RESPONSE; memcpy(&conn->prsp[1], &rsp, sizeof(rsp)); conn->local_key_dist = rsp.resp_key_dist; conn->remote_key_dist = rsp.init_key_dist; if (((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) || conn->addr_type == BDADDR_BREDR) { conn->sc = true; conn->local_key_dist &= ~SC_NO_DIST; conn->remote_key_dist &= ~SC_NO_DIST; } smp_send(conn, BT_L2CAP_SMP_PAIRING_RESPONSE, &rsp, sizeof(rsp)); if (conn->addr_type == BDADDR_BREDR) distribute_keys(conn); } static void pairing_rsp(struct smp_conn *conn, const void *data, uint16_t len) { struct smp *smp = conn->smp; uint8_t cfm[16]; memcpy(conn->prsp, data, sizeof(conn->prsp)); conn->local_key_dist = conn->prsp[5]; conn->remote_key_dist = conn->prsp[6]; if (conn->addr_type == BDADDR_BREDR) { conn->local_key_dist &= ~SC_NO_DIST; conn->remote_key_dist &= ~SC_NO_DIST; distribute_keys(conn); return; } if (((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) || conn->addr_type == BDADDR_BREDR) { conn->sc = true; conn->local_key_dist &= ~SC_NO_DIST; conn->remote_key_dist &= ~SC_NO_DIST; if (conn->addr_type == BDADDR_BREDR) distribute_keys(conn); else send_public_key(conn); return; } bt_crypto_c1(smp->crypto, conn->tk, conn->prnd, conn->prsp, conn->preq, conn->ia_type, conn->ia, conn->ra_type, conn->ra, cfm); smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, cfm, sizeof(cfm)); } static void sc_check_confirm(struct smp_conn *conn) { if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY) { sc_passkey_round(conn, BT_L2CAP_SMP_PAIRING_CONFIRM); return; } if (conn->out) smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, sizeof(conn->prnd)); } static void pairing_cfm(struct smp_conn *conn, const void *data, uint16_t len) { uint8_t rsp[16]; memcpy(conn->pcnf, data + 1, 16); if (conn->sc) { sc_check_confirm(conn); return; } if (conn->out) { memset(rsp, 0, sizeof(rsp)); smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, sizeof(conn->prnd)); } else { bt_crypto_c1(conn->smp->crypto, conn->tk, conn->prnd, conn->prsp, conn->preq, conn->ia_type, conn->ia, conn->ra_type, conn->ra, rsp); smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, rsp, sizeof(rsp)); } } static uint8_t sc_random(struct smp_conn *conn) { /* Passkey entry has special treatment */ if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY) return sc_passkey_round(conn, BT_L2CAP_SMP_PAIRING_RANDOM); if (conn->out) { uint8_t cfm[16]; bt_crypto_f4(conn->smp->crypto, conn->remote_pk, conn->local_pk, conn->rrnd, 0, cfm); if (memcmp(conn->pcnf, cfm, 16)) return 0x04; /* Confirm Value Failed */ } else { smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, 16); } sc_mackey_and_ltk(conn); if (conn->out) sc_dhkey_check(conn); return 0; } static void pairing_rnd(struct smp_conn *conn, const void *data, uint16_t len) { memcpy(conn->rrnd, data + 1, 16); if (conn->sc) { uint8_t reason = sc_random(conn); if (reason) smp_send(conn, BT_L2CAP_SMP_PAIRING_FAILED, &reason, sizeof(reason)); return; } if (!verify_random(conn, data + 1)) return; if (conn->out) return; smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, sizeof(conn->prnd)); } static void encrypt_info(struct smp_conn *conn, const void *data, uint16_t len) { } static void central_ident(struct smp_conn *conn, const void *data, uint16_t len) { conn->remote_key_dist &= ~DIST_ENC_KEY; if (conn->out && !conn->remote_key_dist) distribute_keys(conn); } static void ident_addr_info(struct smp_conn *conn, const void *data, uint16_t len) { } static void ident_info(struct smp_conn *conn, const void *data, uint16_t len) { conn->remote_key_dist &= ~DIST_ID_KEY; if (conn->out && !conn->remote_key_dist) distribute_keys(conn); } static void signing_info(struct smp_conn *conn, const void *data, uint16_t len) { conn->remote_key_dist &= ~DIST_SIGN; if (conn->out && !conn->remote_key_dist) distribute_keys(conn); } static void public_key(struct smp_conn *conn, const void *data, uint16_t len) { struct smp *smp = conn->smp; uint8_t buf[16]; memcpy(conn->remote_pk, data + 1, 64); if (!conn->out) { if (!send_public_key(conn)) return; } if (!ecdh_shared_secret(conn->remote_pk, conn->local_sk, conn->dhkey)) return; conn->method = sc_select_method(conn); if (conn->method == DSP_PASSKEY || conn->method == REQ_PASSKEY) { sc_passkey_round(conn, BT_L2CAP_SMP_PUBLIC_KEY); return; } if (conn->out) return; if (!bt_crypto_f4(smp->crypto, conn->local_pk, conn->remote_pk, conn->prnd, 0, buf)) return; smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, buf, sizeof(buf)); } static void dhkey_check(struct smp_conn *conn, const void *data, uint16_t len) { const struct bt_l2cap_smp_dhkey_check *cmd = data + 1; uint8_t a[7], b[7], *local_addr, *remote_addr; uint8_t io_cap[3], r[16], e[16]; memcpy(a, &conn->ia, 6); memcpy(b, &conn->ra, 6); a[6] = conn->ia_type; b[6] = conn->ra_type; if (conn->out) { local_addr = a; remote_addr = b; memcpy(io_cap, &conn->prsp[1], 3); } else { local_addr = b; remote_addr = a; memcpy(io_cap, &conn->preq[1], 3); } memset(r, 0, sizeof(r)); if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY) put_le32(conn->passkey_notify, r); if (!bt_crypto_f6(conn->smp->crypto, conn->mackey, conn->rrnd, conn->prnd, r, io_cap, remote_addr, local_addr, e)) return; if (memcmp(cmd->e, e, 16)) { uint8_t reason = 0x0b; /* DHKey Check Failed */ smp_send(conn, BT_L2CAP_SMP_PAIRING_FAILED, &reason, sizeof(reason)); } if (conn->out) bthost_le_start_encrypt(conn->smp->bthost, conn->handle, conn->ltk); else sc_dhkey_check(conn); } void smp_pair(void *conn_data, uint8_t io_cap, uint8_t auth_req) { struct smp_conn *conn = conn_data; struct bt_l2cap_smp_pairing_request req; req.io_capa = io_cap; req.oob_data = 0x00; req.auth_req = auth_req; req.max_key_size = 0x10; req.init_key_dist = key_dist(conn->smp->bthost); req.resp_key_dist = key_dist(conn->smp->bthost); conn->preq[0] = BT_L2CAP_SMP_PAIRING_REQUEST; memcpy(&conn->preq[1], &req, sizeof(req)); smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req)); } void smp_data(void *conn_data, const void *data, uint16_t len) { struct smp_conn *conn = conn_data; uint8_t opcode; if (len < 1) { bthost_debug(conn->smp->bthost, "Received too small SMP PDU"); return; } if (conn->addr_type == BDADDR_BREDR) { bthost_debug(conn->smp->bthost, "Received BR/EDR SMP data on LE link"); return; } opcode = *((const uint8_t *) data); switch (opcode) { case BT_L2CAP_SMP_PAIRING_REQUEST: pairing_req(conn, data, len); break; case BT_L2CAP_SMP_PAIRING_RESPONSE: pairing_rsp(conn, data, len); break; case BT_L2CAP_SMP_PAIRING_CONFIRM: pairing_cfm(conn, data, len); break; case BT_L2CAP_SMP_PAIRING_RANDOM: pairing_rnd(conn, data, len); break; case BT_L2CAP_SMP_ENCRYPT_INFO: encrypt_info(conn, data, len); break; case BT_L2CAP_SMP_CENTRAL_IDENT: central_ident(conn, data, len); break; case BT_L2CAP_SMP_IDENT_ADDR_INFO: ident_addr_info(conn, data, len); break; case BT_L2CAP_SMP_IDENT_INFO: ident_info(conn, data, len); break; case BT_L2CAP_SMP_SIGNING_INFO: signing_info(conn, data, len); break; case BT_L2CAP_SMP_PUBLIC_KEY: public_key(conn, data, len); break; case BT_L2CAP_SMP_DHKEY_CHECK: dhkey_check(conn, data, len); break; default: break; } } void smp_bredr_data(void *conn_data, const void *data, uint16_t len) { struct smp_conn *conn = conn_data; uint8_t opcode; if (len < 1) { bthost_debug(conn->smp->bthost, "Received too small SMP PDU"); return; } if (conn->addr_type != BDADDR_BREDR) { bthost_debug(conn->smp->bthost, "Received LE SMP data on BR/EDR link"); return; } opcode = *((const uint8_t *) data); switch (opcode) { case BT_L2CAP_SMP_PAIRING_REQUEST: pairing_req(conn, data, len); break; case BT_L2CAP_SMP_PAIRING_RESPONSE: pairing_rsp(conn, data, len); break; default: break; } } int smp_get_ltk(void *smp_data, uint64_t rand, uint16_t ediv, uint8_t *ltk) { struct smp_conn *conn = smp_data; static const uint8_t no_ltk[16] = { 0 }; if (!memcmp(conn->ltk, no_ltk, 16)) return -ENOENT; memcpy(ltk, conn->ltk, 16); return 0; } static void smp_conn_bredr(struct smp_conn *conn, uint8_t encrypt) { struct smp *smp = conn->smp; struct bt_l2cap_smp_pairing_request req; uint64_t fixed_chan; if (encrypt != 0x02) return; conn->sc = true; if (!conn->out) return; fixed_chan = bthost_conn_get_fixed_chan(smp->bthost, conn->handle); if (!(fixed_chan & L2CAP_FC_SMP_BREDR)) return; memset(&req, 0, sizeof(req)); req.max_key_size = 0x10; req.init_key_dist = key_dist(smp->bthost); req.resp_key_dist = key_dist(smp->bthost); smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req)); } void smp_conn_encrypted(void *conn_data, uint8_t encrypt) { struct smp_conn *conn = conn_data; if (!encrypt) return; if (conn->addr_type == BDADDR_BREDR) { smp_conn_bredr(conn, encrypt); return; } if (conn->out && conn->remote_key_dist) return; distribute_keys(conn); } static uint8_t type2hci(uint8_t addr_type) { switch (addr_type) { case BDADDR_BREDR: case BDADDR_LE_PUBLIC: return LE_PUBLIC_ADDRESS; case BDADDR_LE_RANDOM: return LE_RANDOM_ADDRESS; } return 0x00; } void *smp_conn_add(void *smp_data, uint16_t handle, const uint8_t *ia, uint8_t ia_type, const uint8_t *ra, uint8_t ra_type, bool conn_init) { struct smp *smp = smp_data; struct smp_conn *conn; char ia_str[18], ra_str[18]; conn = malloc(sizeof(struct smp_conn)); if (!conn) return NULL; memset(conn, 0, sizeof(*conn)); conn->smp = smp; conn->handle = handle; conn->out = conn_init; conn->addr_type = conn_init ? ia_type : ra_type; conn->ia_type = type2hci(ia_type); conn->ra_type = type2hci(ra_type); memcpy(conn->ia, ia, 6); memcpy(conn->ra, ra, 6); ba2str((bdaddr_t *) ia, ia_str); ba2str((bdaddr_t *) ra, ra_str); bthost_debug(smp->bthost, "ia %s type 0x%02x ra %s type 0x%02x", ia_str, ia_type, ra_str, ra_type); bt_crypto_random_bytes(smp->crypto, conn->prnd, sizeof(conn->prnd)); return conn; } void smp_conn_del(void *conn_data) { struct smp_conn *conn = conn_data; free(conn); } void *smp_start(struct bthost *bthost) { struct smp *smp; smp = malloc(sizeof(struct smp)); if (!smp) return NULL; memset(smp, 0, sizeof(*smp)); smp->crypto = bt_crypto_new(); if (!smp->crypto) { free(smp); return NULL; } smp->bthost = bthost; return smp; } void smp_stop(void *smp_data) { struct smp *smp = smp_data; bt_crypto_unref(smp->crypto); free(smp); }