Commit a7a595f6 authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by Gustavo F. Padovan

Bluetooth: Add support for LE Start Encryption

This adds support for starting SMP Phase 2 Encryption, when the initial
SMP negotiation is successful. This adds the LE Start Encryption and LE
Long Term Key Request commands and related events.
Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 7d24ddcc
...@@ -745,6 +745,33 @@ struct hci_cp_le_conn_update { ...@@ -745,6 +745,33 @@ struct hci_cp_le_conn_update {
__le16 max_ce_len; __le16 max_ce_len;
} __packed; } __packed;
#define HCI_OP_LE_START_ENC 0x2019
struct hci_cp_le_start_enc {
__le16 handle;
__u8 rand[8];
__le16 ediv;
__u8 ltk[16];
} __packed;
#define HCI_OP_LE_LTK_REPLY 0x201a
struct hci_cp_le_ltk_reply {
__le16 handle;
__u8 ltk[16];
} __packed;
struct hci_rp_le_ltk_reply {
__u8 status;
__le16 handle;
} __packed;
#define HCI_OP_LE_LTK_NEG_REPLY 0x201b
struct hci_cp_le_ltk_neg_reply {
__le16 handle;
} __packed;
struct hci_rp_le_ltk_neg_reply {
__u8 status;
__le16 handle;
} __packed;
/* ---- HCI Events ---- */ /* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01 #define HCI_EV_INQUIRY_COMPLETE 0x01
...@@ -1035,6 +1062,13 @@ struct hci_ev_le_conn_complete { ...@@ -1035,6 +1062,13 @@ struct hci_ev_le_conn_complete {
__u8 clk_accurancy; __u8 clk_accurancy;
} __packed; } __packed;
#define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req {
__le16 handle;
__u8 random[8];
__le16 ediv;
} __packed;
/* Advertising report event types */ /* Advertising report event types */
#define ADV_IND 0x00 #define ADV_IND 0x00
#define ADV_DIRECT_IND 0x01 #define ADV_DIRECT_IND 0x01
......
...@@ -249,6 +249,7 @@ struct hci_conn { ...@@ -249,6 +249,7 @@ struct hci_conn {
__u8 power_save; __u8 power_save;
__u16 disc_timeout; __u16 disc_timeout;
unsigned long pend; unsigned long pend;
__u8 ltk[16];
__u8 remote_cap; __u8 remote_cap;
__u8 remote_oob; __u8 remote_oob;
...@@ -861,4 +862,9 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); ...@@ -861,4 +862,9 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier); u16 latency, u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16]);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
void hci_le_ltk_neg_reply(struct hci_conn *conn);
#endif /* __HCI_CORE_H */ #endif /* __HCI_CORE_H */
...@@ -204,6 +204,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, ...@@ -204,6 +204,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
} }
EXPORT_SYMBOL(hci_le_conn_update); EXPORT_SYMBOL(hci_le_conn_update);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_start_enc cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
cp.ediv = ediv;
memcpy(cp.rand, rand, sizeof(rand));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_start_enc);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(ltk));
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_ltk_reply);
void hci_le_ltk_neg_reply(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_neg_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
}
/* Device _must_ be locked */ /* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status) void hci_sco_setup(struct hci_conn *conn, __u8 status)
{ {
......
...@@ -868,6 +868,30 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, ...@@ -868,6 +868,30 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
}
static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{ {
BT_DBG("%s status 0x%x", hdev->name, status); BT_DBG("%s status 0x%x", hdev->name, status);
...@@ -1248,6 +1272,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -1248,6 +1272,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
}
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 status = *((__u8 *) skb->data); __u8 status = *((__u8 *) skb->data);
...@@ -1856,6 +1885,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1856,6 +1885,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_set_scan_enable(hdev, skb); hci_cc_le_set_scan_enable(hdev, skb);
break; break;
case HCI_OP_LE_LTK_REPLY:
hci_cc_le_ltk_reply(hdev, skb);
break;
case HCI_OP_LE_LTK_NEG_REPLY:
hci_cc_le_ltk_neg_reply(hdev, skb);
break;
default: default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break; break;
...@@ -1934,6 +1971,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1934,6 +1971,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status); hci_cs_le_create_conn(hdev, ev->status);
break; break;
case HCI_OP_LE_START_ENC:
hci_cs_le_start_enc(hdev, ev->status);
break;
default: default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break; break;
...@@ -2745,6 +2786,28 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, ...@@ -2745,6 +2786,28 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_ltk_req *ev = (void *) skb->data;
struct hci_cp_le_ltk_reply cp;
struct hci_conn *conn;
BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk));
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
hci_dev_unlock(hdev);
}
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_le_meta *le_ev = (void *) skb->data; struct hci_ev_le_meta *le_ev = (void *) skb->data;
...@@ -2760,6 +2823,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2760,6 +2823,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_adv_report_evt(hdev, skb); hci_le_adv_report_evt(hdev, skb);
break; break;
case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb);
break;
default: default:
break; break;
} }
......
...@@ -277,13 +277,16 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, ...@@ -277,13 +277,16 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn,
static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; struct hci_conn *hcon = conn->hcon;
struct crypto_blkcipher *tfm = hcon->hdev->tfm;
int ret; int ret;
u8 key[16], res[16], random[16], confirm[16], buf[128]; u8 key[16], res[16], random[16], confirm[16], buf[128];
swap128(skb->data, random); swap128(skb->data, random);
skb_pull(skb, sizeof(random)); skb_pull(skb, sizeof(random));
memset(hcon->ltk, 0, sizeof(hcon->ltk));
if (conn->hcon->out) if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst, conn->src, conn->hcon->dst_type, conn->dst,
...@@ -309,11 +312,15 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -309,11 +312,15 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
} }
if (conn->hcon->out) { if (conn->hcon->out) {
__le16 ediv;
u8 rand[8];
smp_s1(tfm, conn->tk, random, conn->prnd, key); smp_s1(tfm, conn->tk, random, conn->prnd, key);
swap128(key, hcon->ltk);
hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, memset(rand, 0, sizeof(rand));
sizeof(buf), 0); ediv = 0;
BT_DBG("key %s", buf); hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
} else { } else {
u8 r[16]; u8 r[16];
...@@ -321,6 +328,7 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -321,6 +328,7 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
smp_s1(tfm, conn->tk, conn->prnd, random, key); smp_s1(tfm, conn->tk, conn->prnd, random, key);
swap128(key, hcon->ltk);
hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0); sizeof(buf), 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment