diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2011-06-09 17:50:47 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 14:48:25 -0400 |
commit | a7a595f675f1b33dc73167147321dba5c4395acc (patch) | |
tree | ee17d1ba777fd18ec7b666a356b00c131cb5f0f2 /net/bluetooth | |
parent | 7d24ddcc1140d2f796436e476c8d69469610588b (diff) |
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: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_conn.c | 49 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 67 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 16 |
3 files changed, 128 insertions, 4 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 37f5a174f072..18193831bbf1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -204,6 +204,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, | |||
204 | } | 204 | } |
205 | EXPORT_SYMBOL(hci_le_conn_update); | 205 | EXPORT_SYMBOL(hci_le_conn_update); |
206 | 206 | ||
207 | void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], | ||
208 | __u8 ltk[16]) | ||
209 | { | ||
210 | struct hci_dev *hdev = conn->hdev; | ||
211 | struct hci_cp_le_start_enc cp; | ||
212 | |||
213 | BT_DBG("%p", conn); | ||
214 | |||
215 | memset(&cp, 0, sizeof(cp)); | ||
216 | |||
217 | cp.handle = cpu_to_le16(conn->handle); | ||
218 | memcpy(cp.ltk, ltk, sizeof(cp.ltk)); | ||
219 | cp.ediv = ediv; | ||
220 | memcpy(cp.rand, rand, sizeof(rand)); | ||
221 | |||
222 | hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); | ||
223 | } | ||
224 | EXPORT_SYMBOL(hci_le_start_enc); | ||
225 | |||
226 | void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]) | ||
227 | { | ||
228 | struct hci_dev *hdev = conn->hdev; | ||
229 | struct hci_cp_le_ltk_reply cp; | ||
230 | |||
231 | BT_DBG("%p", conn); | ||
232 | |||
233 | memset(&cp, 0, sizeof(cp)); | ||
234 | |||
235 | cp.handle = cpu_to_le16(conn->handle); | ||
236 | memcpy(cp.ltk, ltk, sizeof(ltk)); | ||
237 | |||
238 | hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); | ||
239 | } | ||
240 | EXPORT_SYMBOL(hci_le_ltk_reply); | ||
241 | |||
242 | void hci_le_ltk_neg_reply(struct hci_conn *conn) | ||
243 | { | ||
244 | struct hci_dev *hdev = conn->hdev; | ||
245 | struct hci_cp_le_ltk_neg_reply cp; | ||
246 | |||
247 | BT_DBG("%p", conn); | ||
248 | |||
249 | memset(&cp, 0, sizeof(cp)); | ||
250 | |||
251 | cp.handle = cpu_to_le16(conn->handle); | ||
252 | |||
253 | hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp); | ||
254 | } | ||
255 | |||
207 | /* Device _must_ be locked */ | 256 | /* Device _must_ be locked */ |
208 | void hci_sco_setup(struct hci_conn *conn, __u8 status) | 257 | void hci_sco_setup(struct hci_conn *conn, __u8 status) |
209 | { | 258 | { |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0f643f84131f..166fa113721c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -868,6 +868,30 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
868 | hci_dev_unlock(hdev); | 868 | hci_dev_unlock(hdev); |
869 | } | 869 | } |
870 | 870 | ||
871 | static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) | ||
872 | { | ||
873 | struct hci_rp_le_ltk_reply *rp = (void *) skb->data; | ||
874 | |||
875 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
876 | |||
877 | if (rp->status) | ||
878 | return; | ||
879 | |||
880 | hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status); | ||
881 | } | ||
882 | |||
883 | static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) | ||
884 | { | ||
885 | struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data; | ||
886 | |||
887 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
888 | |||
889 | if (rp->status) | ||
890 | return; | ||
891 | |||
892 | hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); | ||
893 | } | ||
894 | |||
871 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 895 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
872 | { | 896 | { |
873 | BT_DBG("%s status 0x%x", hdev->name, status); | 897 | 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 | hci_dev_unlock(hdev); | 1272 | hci_dev_unlock(hdev); |
1249 | } | 1273 | } |
1250 | 1274 | ||
1275 | static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) | ||
1276 | { | ||
1277 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
1278 | } | ||
1279 | |||
1251 | static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1280 | static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1252 | { | 1281 | { |
1253 | __u8 status = *((__u8 *) skb->data); | 1282 | __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 | hci_cc_le_set_scan_enable(hdev, skb); | 1885 | hci_cc_le_set_scan_enable(hdev, skb); |
1857 | break; | 1886 | break; |
1858 | 1887 | ||
1888 | case HCI_OP_LE_LTK_REPLY: | ||
1889 | hci_cc_le_ltk_reply(hdev, skb); | ||
1890 | break; | ||
1891 | |||
1892 | case HCI_OP_LE_LTK_NEG_REPLY: | ||
1893 | hci_cc_le_ltk_neg_reply(hdev, skb); | ||
1894 | break; | ||
1895 | |||
1859 | default: | 1896 | default: |
1860 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1897 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1861 | break; | 1898 | break; |
@@ -1934,6 +1971,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1934 | hci_cs_le_create_conn(hdev, ev->status); | 1971 | hci_cs_le_create_conn(hdev, ev->status); |
1935 | break; | 1972 | break; |
1936 | 1973 | ||
1974 | case HCI_OP_LE_START_ENC: | ||
1975 | hci_cs_le_start_enc(hdev, ev->status); | ||
1976 | break; | ||
1977 | |||
1937 | default: | 1978 | default: |
1938 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1979 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1939 | break; | 1980 | break; |
@@ -2745,6 +2786,28 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, | |||
2745 | hci_dev_unlock(hdev); | 2786 | hci_dev_unlock(hdev); |
2746 | } | 2787 | } |
2747 | 2788 | ||
2789 | static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, | ||
2790 | struct sk_buff *skb) | ||
2791 | { | ||
2792 | struct hci_ev_le_ltk_req *ev = (void *) skb->data; | ||
2793 | struct hci_cp_le_ltk_reply cp; | ||
2794 | struct hci_conn *conn; | ||
2795 | |||
2796 | BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); | ||
2797 | |||
2798 | hci_dev_lock(hdev); | ||
2799 | |||
2800 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | ||
2801 | |||
2802 | memset(&cp, 0, sizeof(cp)); | ||
2803 | cp.handle = cpu_to_le16(conn->handle); | ||
2804 | memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk)); | ||
2805 | |||
2806 | hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); | ||
2807 | |||
2808 | hci_dev_unlock(hdev); | ||
2809 | } | ||
2810 | |||
2748 | static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2811 | static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) |
2749 | { | 2812 | { |
2750 | struct hci_ev_le_meta *le_ev = (void *) skb->data; | 2813 | 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 | hci_le_adv_report_evt(hdev, skb); | 2823 | hci_le_adv_report_evt(hdev, skb); |
2761 | break; | 2824 | break; |
2762 | 2825 | ||
2826 | case HCI_EV_LE_LTK_REQ: | ||
2827 | hci_le_ltk_request_evt(hdev, skb); | ||
2828 | break; | ||
2829 | |||
2763 | default: | 2830 | default: |
2764 | break; | 2831 | break; |
2765 | } | 2832 | } |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7a9a195c27d3..56828db68109 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -277,13 +277,16 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, | |||
277 | 277 | ||
278 | static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | 278 | static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) |
279 | { | 279 | { |
280 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; | 280 | struct hci_conn *hcon = conn->hcon; |
281 | struct crypto_blkcipher *tfm = hcon->hdev->tfm; | ||
281 | int ret; | 282 | int ret; |
282 | u8 key[16], res[16], random[16], confirm[16], buf[128]; | 283 | u8 key[16], res[16], random[16], confirm[16], buf[128]; |
283 | 284 | ||
284 | swap128(skb->data, random); | 285 | swap128(skb->data, random); |
285 | skb_pull(skb, sizeof(random)); | 286 | skb_pull(skb, sizeof(random)); |
286 | 287 | ||
288 | memset(hcon->ltk, 0, sizeof(hcon->ltk)); | ||
289 | |||
287 | if (conn->hcon->out) | 290 | if (conn->hcon->out) |
288 | ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, | 291 | ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, |
289 | conn->src, conn->hcon->dst_type, conn->dst, | 292 | 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 | } | 312 | } |
310 | 313 | ||
311 | if (conn->hcon->out) { | 314 | if (conn->hcon->out) { |
315 | __le16 ediv; | ||
316 | u8 rand[8]; | ||
317 | |||
312 | smp_s1(tfm, conn->tk, random, conn->prnd, key); | 318 | smp_s1(tfm, conn->tk, random, conn->prnd, key); |
319 | swap128(key, hcon->ltk); | ||
313 | 320 | ||
314 | hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, | 321 | memset(rand, 0, sizeof(rand)); |
315 | sizeof(buf), 0); | 322 | ediv = 0; |
316 | BT_DBG("key %s", buf); | 323 | hci_le_start_enc(hcon, ediv, rand, hcon->ltk); |
317 | } else { | 324 | } else { |
318 | u8 r[16]; | 325 | u8 r[16]; |
319 | 326 | ||
@@ -321,6 +328,7 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |||
321 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); | 328 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); |
322 | 329 | ||
323 | smp_s1(tfm, conn->tk, conn->prnd, random, key); | 330 | smp_s1(tfm, conn->tk, conn->prnd, random, key); |
331 | swap128(key, hcon->ltk); | ||
324 | 332 | ||
325 | hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, | 333 | hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, |
326 | sizeof(buf), 0); | 334 | sizeof(buf), 0); |