Return-Path: Date: Tue, 7 Dec 2010 15:38:00 -0200 From: "Gustavo F. Padovan" To: Vinicius Costa Gomes Cc: linux-bluetooth@vger.kernel.org Subject: Re: [RFC v2 8/9] Bluetooth: Add support for LE Start Encryption Message-ID: <20101207173800.GG2944@vigoh> References: <1291671832-13435-1-git-send-email-vinicius.gomes@openbossa.org> <1291671832-13435-9-git-send-email-vinicius.gomes@openbossa.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii In-Reply-To: <1291671832-13435-9-git-send-email-vinicius.gomes@openbossa.org> Sender: linux-bluetooth-owner@vger.kernel.org List-ID: Hi Vinicius, * Vinicius Costa Gomes [2010-12-06 18:43:51 -0300]: > 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: Vinicius Costa Gomes > --- > include/net/bluetooth/hci.h | 34 +++++++++++++++++++ > include/net/bluetooth/hci_core.h | 5 +++ > net/bluetooth/hci_conn.c | 47 ++++++++++++++++++++++++++ > net/bluetooth/hci_event.c | 67 ++++++++++++++++++++++++++++++++++++++ > net/bluetooth/smp.c | 8 ++++- > 5 files changed, 160 insertions(+), 1 deletions(-) > > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h > index dff6ded..e6bed3f 100644 > --- a/include/net/bluetooth/hci.h > +++ b/include/net/bluetooth/hci.h > @@ -626,6 +626,33 @@ struct hci_cp_le_create_conn { > > #define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e > > +#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 ---- */ > #define HCI_EV_INQUIRY_COMPLETE 0x01 > > @@ -897,6 +924,13 @@ struct hci_ev_le_conn_complete { > __u8 clk_accurancy; > } __packed; > > +#define HCI_EV_LE_LTK_REQ 0x05 > +struct hci_ev_le_ltk_req { > + __le16 handle; > + __u8 random[8]; > + __le16 ediv; > +} __packed; > + > /* Internal events generated by Bluetooth stack */ > #define HCI_EV_STACK_INTERNAL 0xfd > struct hci_ev_stack_internal { > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h > index d0a9f5d..c6c44eb 100644 > --- a/include/net/bluetooth/hci_core.h > +++ b/include/net/bluetooth/hci_core.h > @@ -192,6 +192,7 @@ struct hci_conn { > __u8 sec_level; > __u8 power_save; > __u16 disc_timeout; > + __u8 ltk[16]; > unsigned long pend; > > unsigned int sent; > @@ -713,4 +714,8 @@ struct hci_sec_filter { > > void hci_req_complete(struct hci_dev *hdev, int result); > > +void hci_le_start_enc(struct hci_conn *conn, 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 */ > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c > index edfb48b..f919ddb 100644 > --- a/net/bluetooth/hci_conn.c > +++ b/net/bluetooth/hci_conn.c > @@ -183,6 +183,53 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) > hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); > } > > +void hci_le_start_enc(struct hci_conn *conn, 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, 16); > + > + 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); > +} > +EXPORT_SYMBOL(hci_le_ltk_neg_reply); > + > /* Device _must_ be locked */ > void hci_sco_setup(struct hci_conn *conn, __u8 status) > { > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c > index 55cdd6a..c90696f 100644 > --- a/net/bluetooth/hci_event.c > +++ b/net/bluetooth/hci_event.c > @@ -559,6 +559,30 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, > hci_req_complete(hdev, rp->status); > } > > +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, 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, rp->status); > +} > + > static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) > { > BT_DBG("%s status 0x%x", hdev->name, status); > @@ -920,6 +944,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) > 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) > { > __u8 status = *((__u8 *) skb->data); > @@ -1440,6 +1469,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk > hci_cc_le_read_buffer_size(hdev, skb); > 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: > BT_DBG("%s opcode 0x%x", hdev->name, opcode); > break; > @@ -1510,6 +1547,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) > hci_cs_le_create_conn(hdev, ev->status); > break; > > + case HCI_OP_LE_START_ENC: > + hci_cs_le_start_enc(hdev, ev->status); > + break; > + > default: > BT_DBG("%s opcode 0x%x", hdev->name, opcode); > break; > @@ -2013,6 +2054,28 @@ unlock: > 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) > { > struct hci_ev_le_meta *le_ev = (void *) skb->data; > @@ -2024,6 +2087,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) > hci_le_conn_complete_evt(hdev, skb); > break; > > + case HCI_EV_LE_LTK_REQ: > + hci_le_ltk_request_evt(hdev, skb); > + break; > + > default: > break; > } > diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c > index 7d7e8ad..d19b8a2 100644 > --- a/net/bluetooth/smp.c > +++ b/net/bluetooth/smp.c > @@ -289,7 +289,8 @@ static void smp_cmd_pairing_confirm(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; > u8 k[16], key[16], res[16], random[16], confirm[16], buf[128]; > > @@ -297,6 +298,7 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) > skb_pull(skb, 16); > > memset(k, 0, sizeof(k)); > + memset(hcon->ltk, 0, sizeof(hcon->ltk)); > > if (conn->hcon->out) > ret = smp_c1(tfm, k, random, conn->preq, conn->pres, 0, > @@ -320,6 +322,9 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) > > if (conn->hcon->out) { > smp_s1(tfm, k, random, conn->prnd, key); > + swap128(key, hcon->ltk); > + > + hci_le_start_enc(conn->hcon, hcon->ltk); You have hcon here, no need to use conn->hcon. -- Gustavo F. Padovan http://profusion.mobi