diff --git a/emulator/bthost.c b/emulator/bthost.c
index 22bff54..e1b8a5a 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
}
conn->smp_data = smp_conn_add(bthost->smp_data, handle, ia, ra,
- bthost->conn_init);
+ addr_type, bthost->conn_init);
if (bthost->new_conn_cb)
bthost->new_conn_cb(conn->handle, bthost->new_conn_data);
case 0x0006:
smp_data(conn->smp_data, l2_data, l2_len);
break;
+ case 0x0007:
+ smp_bredr_data(conn->smp_data, l2_data, l2_len);
+ break;
default:
l2conn = btconn_find_l2cap_conn_by_scid(conn, cid);
if (l2conn && l2conn->psm == 0x0003)
diff --git a/emulator/bthost.h b/emulator/bthost.h
index e2d683b..207ce77 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
void *smp_start(struct bthost *bthost);
void smp_stop(void *smp_data);
void *smp_conn_add(void *smp_data, uint16_t handle, const uint8_t *ia,
- const uint8_t *ra, bool conn_init);
+ const uint8_t *ra, uint8_t addr_type, bool conn_init);
void smp_conn_del(void *conn_data);
void smp_conn_encrypted(void *conn_data, uint8_t encrypt);
void smp_data(void *conn_data, const void *data, uint16_t len);
+void smp_bredr_data(void *conn_data, const void *data, uint16_t len);
int smp_get_ltk(void *smp_data, uint64_t rand, uint16_t ediv, uint8_t *ltk);
void smp_pair(void *conn_data, uint8_t io_cap, uint8_t auth_req);
diff --git a/emulator/smp.c b/emulator/smp.c
index 4b66ec9..5d338b7 100644
--- a/emulator/smp.c
+++ b/emulator/smp.c
#include "monitor/bt.h"
#include "bthost.h"
-#define SMP_CID 0x0006
+#define SMP_CID 0x0006
+#define SMP_BREDR_CID 0x0007
#define SMP_PASSKEY_ENTRY_FAILED 0x01
#define SMP_OOB_NOT_AVAIL 0x02
struct smp_conn {
struct smp *smp;
uint16_t handle;
+ uint8_t addr_type;
bool out;
bool sc;
bool initiator;
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;
- bthost_send_cid_v(conn->smp->bthost, conn->handle, SMP_CID, iov, 2);
+ 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)
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_MASTER_IDENT, buf, 10);
+ }
+
+ if (conn->local_key_dist & DIST_ID_KEY) {
+ 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);
+
+ memset(buf, 0, sizeof(buf));
+ smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf));
+ }
+
+ 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;
memcpy(conn->preq, data, sizeof(conn->preq));
- rsp.io_capa = bthost_get_io_capability(bthost);
- rsp.oob_data = 0x00;
- rsp.auth_req = bthost_get_auth_req(bthost);
+ 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;
rsp.resp_key_dist = conn->preq[6] & KEY_DIST;
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)) {
+ 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)
conn->local_key_dist = conn->prsp[5];
conn->remote_key_dist = conn->prsp[6];
- if ((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) {
+ 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;
- send_public_key(conn);
+ if (conn->addr_type == BDADDR_BREDR)
+ distribute_keys(conn);
+ else
+ send_public_key(conn);
return;
}
smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, rsp, sizeof(rsp));
}
-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_MASTER_IDENT, buf, 10);
- }
-
- if (conn->local_key_dist & DIST_ID_KEY) {
- 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);
-
- memset(buf, 0, sizeof(buf));
- smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf));
- }
-
- 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 encrypt_info(struct smp_conn *conn, const void *data, uint16_t len)
{
}
return;
}
+ if (conn->addr_type == BDADDR_BREDR) {
+ printf("Received BR/EDR SMP data on LE link\n");
+ return;
+ }
+
opcode = *((const uint8_t *) data);
switch (opcode) {
}
}
+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) {
+ printf("Received too small SMP PDU\n");
+ return;
+ }
+
+ if (conn->addr_type != BDADDR_BREDR) {
+ printf("Received LE SMP data on BR/EDR link\n");
+ 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;
}
void *smp_conn_add(void *smp_data, uint16_t handle, const uint8_t *ia,
- const uint8_t *ra, bool conn_init)
+ const uint8_t *ra, uint8_t addr_type, bool conn_init)
{
struct smp *smp = smp_data;
struct smp_conn *conn;
conn->smp = smp;
conn->handle = handle;
+ conn->addr_type = addr_type;
conn->out = conn_init;
conn->ia_type = LE_PUBLIC_ADDRESS;