Skip to content

Commit

Permalink
Bluetooth: Move SMP fields to a separate structure
Browse files Browse the repository at this point in the history
The objective is to make the core to have as little as possible
information about SMP procedures and logic. Now, all the SMP
specific information is hidden from the core.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
  • Loading branch information
Vinicius Costa Gomes authored and Gustavo F. Padovan committed Sep 21, 2011
1 parent 142c69c commit 1c1def0
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 71 deletions.
2 changes: 0 additions & 2 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,6 @@ struct hci_dev {

__u16 init_last_cmd;

struct crypto_blkcipher *tfm;

struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
Expand Down
8 changes: 1 addition & 7 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,14 +409,8 @@ struct l2cap_conn {

__u8 disc_reason;

__u8 preq[7]; /* SMP Pairing Request */
__u8 prsp[7]; /* SMP Pairing Response */
__u8 prnd[16]; /* SMP Pairing Random */
__u8 pcnf[16]; /* SMP Pairing Confirm */
__u8 tk[16]; /* SMP Temporary Key */
__u8 smp_key_size;

struct timer_list security_timer;
struct smp_chan *smp_chan;

struct list_head chan_l;
rwlock_t chan_lock;
Expand Down
10 changes: 10 additions & 0 deletions include/net/bluetooth/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16

struct smp_chan {
u8 preq[7]; /* SMP Pairing Request */
u8 prsp[7]; /* SMP Pairing Response */
u8 prnd[16]; /* SMP Pairing Random */
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
u8 smp_key_size;
struct crypto_blkcipher *tfm;
};

/* SMP Commands */
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
Expand Down
8 changes: 0 additions & 8 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1523,11 +1523,6 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue)
goto nomem;

hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm));

hci_register_sysfs(hdev);

hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
Expand Down Expand Up @@ -1576,9 +1571,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
!test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id);

if (!IS_ERR(hdev->tfm))
crypto_free_blkcipher(hdev->tfm);

hci_notify(hdev, HCI_DEV_UNREG);

if (hdev->rfkill) {
Expand Down
108 changes: 54 additions & 54 deletions net/bluetooth/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,27 +232,30 @@ static void build_pairing_cmd(struct l2cap_conn *conn,

static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
struct smp_chan *smp = conn->smp_chan;

if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;

conn->smp_key_size = max_key_size;
smp->smp_key_size = max_key_size;

return 0;
}

static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
struct smp_chan *smp = conn->smp_chan;
u8 key_size;

BT_DBG("conn %p", conn);

if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
hci_conn_hold(conn->hcon);

conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], req, sizeof(*req));
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req));

if (req->oob_flag)
Expand All @@ -266,10 +269,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_ENC_KEY_SIZE;

/* Just works */
memset(conn->tk, 0, sizeof(conn->tk));
memset(smp->tk, 0, sizeof(smp->tk));

conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&smp->prsp[1], &rsp, sizeof(rsp));

smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);

Expand All @@ -280,15 +283,17 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
struct smp_cmd_pairing_confirm cp;
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
struct smp_chan *smp = conn->smp_chan;
struct crypto_blkcipher *tfm = smp->tfm;

int ret;
u8 res[16], key_size;

BT_DBG("conn %p", conn);

skb_pull(skb, sizeof(*rsp));

req = (void *) &conn->preq[1];
req = (void *) &smp->preq[1];

key_size = min(req->max_key_size, rsp->max_key_size);
if (check_enc_key_size(conn, key_size))
Expand All @@ -298,16 +303,16 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_OOB_NOT_AVAIL;

/* Just works */
memset(conn->tk, 0, sizeof(conn->tk));
memset(smp->tk, 0, sizeof(smp->tk));

conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&smp->prsp[1], rsp, sizeof(*rsp));

ret = smp_rand(conn->prnd);
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;

ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst, res);
if (ret)
return SMP_UNSPECIFIED;
Expand All @@ -321,29 +326,30 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)

static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
struct smp_chan *smp = conn->smp_chan;
struct crypto_blkcipher *tfm = smp->tfm;

BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");

memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
skb_pull(skb, sizeof(conn->pcnf));
memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
skb_pull(skb, sizeof(smp->pcnf));

if (conn->hcon->out) {
u8 random[16];

swap128(conn->prnd, random);
swap128(smp->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else {
struct smp_cmd_pairing_confirm cp;
int ret;
u8 res[16];

ret = smp_rand(conn->prnd);
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;

ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
conn->hcon->dst_type, conn->dst,
0, conn->src, res);
if (ret)
Expand All @@ -360,19 +366,20 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct hci_conn *hcon = conn->hcon;
struct crypto_blkcipher *tfm = hcon->hdev->tfm;
struct smp_chan *smp = conn->smp_chan;
struct crypto_blkcipher *tfm = smp->tfm;
int ret;
u8 key[16], res[16], random[16], confirm[16];

swap128(skb->data, random);
skb_pull(skb, sizeof(random));

if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
ret = smp_c1(tfm, smp->tk, random, smp->preq, smp->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst,
res);
else
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
ret = smp_c1(tfm, smp->tk, random, smp->preq, smp->prsp,
conn->hcon->dst_type, conn->dst, 0, conn->src,
res);
if (ret)
Expand All @@ -382,7 +389,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)

swap128(res, confirm);

if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
BT_ERR("Pairing failed (confirmation values mismatch)");
return SMP_CONFIRM_FAILED;
}
Expand All @@ -394,34 +401,34 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
memset(rand, 0, sizeof(rand));
ediv = 0;

smp_s1(tfm, conn->tk, random, conn->prnd, key);
smp_s1(tfm, smp->tk, random, smp->prnd, key);
swap128(key, stk);

memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
memset(stk + smp->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);

if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return SMP_UNSPECIFIED;

hci_le_start_enc(hcon, ediv, rand, stk);
hcon->enc_key_size = conn->smp_key_size;
hcon->enc_key_size = smp->smp_key_size;
} else {
u8 stk[16], r[16], rand[8];
__le16 ediv;

memset(rand, 0, sizeof(rand));
ediv = 0;

swap128(conn->prnd, r);
swap128(smp->prnd, r);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);

smp_s1(tfm, conn->tk, conn->prnd, random, key);
smp_s1(tfm, smp->tk, smp->prnd, random, key);
swap128(key, stk);

memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
memset(stk + smp->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);

hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
hci_add_ltk(conn->hcon->hdev, 0, conn->dst, smp->smp_key_size,
ediv, rand, stk);
}

Expand All @@ -433,6 +440,7 @@ 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 = conn->smp_chan;

BT_DBG("conn %p", conn);

Expand All @@ -446,8 +454,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
memset(&cp, 0, sizeof(cp));
build_pairing_cmd(conn, &cp, NULL, rp->auth_req);

conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
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);

Expand All @@ -457,16 +465,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
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 (IS_ERR(hcon->hdev->tfm))
return 1;

if (sec_level == BT_SECURITY_LOW)
return 1;

Expand Down Expand Up @@ -505,8 +511,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
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));
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 {
Expand All @@ -524,22 +530,24 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
struct smp_chan *smp = conn->smp_chan;

skb_pull(skb, sizeof(*rp));

memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
memcpy(smp->tk, rp->ltk, sizeof(smp->tk));

return 0;
}

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_chan *smp = conn->smp_chan;

skb_pull(skb, sizeof(*rp));

hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
rp->ediv, rp->rand, conn->tk);
hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
rp->ediv, rp->rand, smp->tk);

smp_distribute_keys(conn, 1);

Expand All @@ -558,12 +566,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
goto done;
}

if (IS_ERR(conn->hcon->hdev->tfm)) {
err = PTR_ERR(conn->hcon->hdev->tfm);
reason = SMP_PAIRING_NOTSUPP;
goto done;
}

skb_pull(skb, sizeof(code));

switch (code) {
Expand Down Expand Up @@ -627,23 +629,21 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
{
struct smp_cmd_pairing *req, *rsp;
struct smp_chan *smp = conn->smp_chan;
__u8 *keydist;

BT_DBG("conn %p force %d", conn, force);

if (IS_ERR(conn->hcon->hdev->tfm))
return PTR_ERR(conn->hcon->hdev->tfm);

if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
return 0;

rsp = (void *) &conn->prsp[1];
rsp = (void *) &smp->prsp[1];

/* The responder sends its keys first */
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
return 0;

req = (void *) &conn->preq[1];
req = (void *) &smp->preq[1];

if (conn->hcon->out) {
keydist = &rsp->init_key_dist;
Expand All @@ -667,7 +667,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)

smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);

hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
ediv, ident.rand, enc.ltk);

ident.ediv = cpu_to_le16(ediv);
Expand Down

0 comments on commit 1c1def0

Please sign in to comment.