blob: 8c225ef349cd733614dfeaca0f2f1bceccdae064 [file] [log] [blame]
Anderson Brigliaeb492e02011-06-09 18:50:40 -03001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
Gustavo Padovan8c520a52012-05-23 04:04:22 -030023#include <linux/crypto.h>
24#include <linux/scatterlist.h>
25#include <crypto/b128ops.h>
26
Anderson Brigliaeb492e02011-06-09 18:50:40 -030027#include <net/bluetooth/bluetooth.h>
28#include <net/bluetooth/hci_core.h>
29#include <net/bluetooth/l2cap.h>
Brian Gix2b64d152011-12-21 16:12:12 -080030#include <net/bluetooth/mgmt.h>
Anderson Brigliaeb492e02011-06-09 18:50:40 -030031#include <net/bluetooth/smp.h>
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030032
Marcel Holtmann17b02e62012-03-01 14:32:37 -080033#define SMP_TIMEOUT msecs_to_jiffies(30000)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -030034
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030035static inline void swap128(u8 src[16], u8 dst[16])
36{
37 int i;
38 for (i = 0; i < 16; i++)
39 dst[15 - i] = src[i];
40}
41
42static inline void swap56(u8 src[7], u8 dst[7])
43{
44 int i;
45 for (i = 0; i < 7; i++)
46 dst[6 - i] = src[i];
47}
48
49static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
50{
51 struct blkcipher_desc desc;
52 struct scatterlist sg;
53 int err, iv_len;
54 unsigned char iv[128];
55
56 if (tfm == NULL) {
57 BT_ERR("tfm %p", tfm);
58 return -EINVAL;
59 }
60
61 desc.tfm = tfm;
62 desc.flags = 0;
63
64 err = crypto_blkcipher_setkey(tfm, k, 16);
65 if (err) {
66 BT_ERR("cipher setkey failed: %d", err);
67 return err;
68 }
69
70 sg_init_one(&sg, r, 16);
71
72 iv_len = crypto_blkcipher_ivsize(tfm);
73 if (iv_len) {
74 memset(&iv, 0xff, iv_len);
75 crypto_blkcipher_set_iv(tfm, iv, iv_len);
76 }
77
78 err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
79 if (err)
80 BT_ERR("Encrypt data error %d", err);
81
82 return err;
83}
84
85static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
86 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
87 u8 _rat, bdaddr_t *ra, u8 res[16])
88{
89 u8 p1[16], p2[16];
90 int err;
91
92 memset(p1, 0, 16);
93
94 /* p1 = pres || preq || _rat || _iat */
95 swap56(pres, p1);
96 swap56(preq, p1 + 7);
97 p1[14] = _rat;
98 p1[15] = _iat;
99
100 memset(p2, 0, 16);
101
102 /* p2 = padding || ia || ra */
103 baswap((bdaddr_t *) (p2 + 4), ia);
104 baswap((bdaddr_t *) (p2 + 10), ra);
105
106 /* res = r XOR p1 */
107 u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
108
109 /* res = e(k, res) */
110 err = smp_e(tfm, k, res);
111 if (err) {
112 BT_ERR("Encrypt data error");
113 return err;
114 }
115
116 /* res = res XOR p2 */
117 u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
118
119 /* res = e(k, res) */
120 err = smp_e(tfm, k, res);
121 if (err)
122 BT_ERR("Encrypt data error");
123
124 return err;
125}
126
127static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
128 u8 r1[16], u8 r2[16], u8 _r[16])
129{
130 int err;
131
132 /* Just least significant octets from r1 and r2 are considered */
133 memcpy(_r, r1 + 8, 8);
134 memcpy(_r + 8, r2 + 8, 8);
135
136 err = smp_e(tfm, k, _r);
137 if (err)
138 BT_ERR("Encrypt data error");
139
140 return err;
141}
142
143static int smp_rand(u8 *buf)
144{
145 get_random_bytes(buf, 16);
146
147 return 0;
148}
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300149
150static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
151 u16 dlen, void *data)
152{
153 struct sk_buff *skb;
154 struct l2cap_hdr *lh;
155 int len;
156
157 len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
158
159 if (len > conn->mtu)
160 return NULL;
161
162 skb = bt_skb_alloc(len, GFP_ATOMIC);
163 if (!skb)
164 return NULL;
165
166 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
167 lh->len = cpu_to_le16(sizeof(code) + dlen);
168 lh->cid = cpu_to_le16(L2CAP_CID_SMP);
169
170 memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
171
172 memcpy(skb_put(skb, dlen), data, dlen);
173
174 return skb;
175}
176
177static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
178{
179 struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
180
181 BT_DBG("code 0x%2.2x", code);
182
183 if (!skb)
184 return;
185
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200186 skb->priority = HCI_PRIO_MAX;
187 hci_send_acl(conn->hchan, skb, 0);
Vinicius Costa Gomese2dcd112011-08-19 21:06:50 -0300188
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -0200189 cancel_delayed_work_sync(&conn->security_timer);
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800190 schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300191}
192
Brian Gix2b64d152011-12-21 16:12:12 -0800193static __u8 authreq_to_seclevel(__u8 authreq)
194{
195 if (authreq & SMP_AUTH_MITM)
196 return BT_SECURITY_HIGH;
197 else
198 return BT_SECURITY_MEDIUM;
199}
200
201static __u8 seclevel_to_authreq(__u8 sec_level)
202{
203 switch (sec_level) {
204 case BT_SECURITY_HIGH:
205 return SMP_AUTH_MITM | SMP_AUTH_BONDING;
206 case BT_SECURITY_MEDIUM:
207 return SMP_AUTH_BONDING;
208 default:
209 return SMP_AUTH_NONE;
210 }
211}
212
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300213static void build_pairing_cmd(struct l2cap_conn *conn,
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300214 struct smp_cmd_pairing *req,
215 struct smp_cmd_pairing *rsp,
216 __u8 authreq)
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300217{
Brian Gix2b64d152011-12-21 16:12:12 -0800218 u8 dist_keys = 0;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300219
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200220 if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
Vinicius Costa Gomesca10b5e2011-08-25 20:02:37 -0300221 dist_keys = SMP_DIST_ENC_KEY;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300222 authreq |= SMP_AUTH_BONDING;
Brian Gix2b64d152011-12-21 16:12:12 -0800223 } else {
224 authreq &= ~SMP_AUTH_BONDING;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300225 }
226
227 if (rsp == NULL) {
228 req->io_capability = conn->hcon->io_capability;
229 req->oob_flag = SMP_OOB_NOT_PRESENT;
230 req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
Brian Gix2b64d152011-12-21 16:12:12 -0800231 req->init_key_dist = 0;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300232 req->resp_key_dist = dist_keys;
233 req->auth_req = authreq;
234 return;
235 }
236
237 rsp->io_capability = conn->hcon->io_capability;
238 rsp->oob_flag = SMP_OOB_NOT_PRESENT;
239 rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
Brian Gix2b64d152011-12-21 16:12:12 -0800240 rsp->init_key_dist = 0;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300241 rsp->resp_key_dist = req->resp_key_dist & dist_keys;
242 rsp->auth_req = authreq;
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300243}
244
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300245static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
246{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300247 struct smp_chan *smp = conn->smp_chan;
248
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300249 if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
250 (max_key_size < SMP_MIN_ENC_KEY_SIZE))
251 return SMP_ENC_KEY_SIZE;
252
Vinicius Costa Gomesf7aa6112012-01-30 19:29:12 -0300253 smp->enc_key_size = max_key_size;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300254
255 return 0;
256}
257
Brian Gix4f957a72011-11-23 08:28:36 -0800258static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
259{
Johan Hedbergbab73cb2012-02-09 16:07:29 +0200260 struct hci_conn *hcon = conn->hcon;
261
Brian Gix4f957a72011-11-23 08:28:36 -0800262 if (send)
263 smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
264 &reason);
265
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200266 clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
Johan Hedbergbab73cb2012-02-09 16:07:29 +0200267 mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300268 hcon->dst_type, reason);
Vinicius Costa Gomesf1c09c02012-02-01 18:27:56 -0300269
Andre Guedes61a0cfb2012-08-01 20:34:15 -0300270 cancel_delayed_work_sync(&conn->security_timer);
271
272 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
Vinicius Costa Gomesf1c09c02012-02-01 18:27:56 -0300273 smp_chan_destroy(conn);
Brian Gix4f957a72011-11-23 08:28:36 -0800274}
275
Brian Gix2b64d152011-12-21 16:12:12 -0800276#define JUST_WORKS 0x00
277#define JUST_CFM 0x01
278#define REQ_PASSKEY 0x02
279#define CFM_PASSKEY 0x03
280#define REQ_OOB 0x04
281#define OVERLAP 0xFF
282
283static const u8 gen_method[5][5] = {
284 { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
285 { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
286 { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
287 { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
288 { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
289};
290
291static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
292 u8 local_io, u8 remote_io)
293{
294 struct hci_conn *hcon = conn->hcon;
295 struct smp_chan *smp = conn->smp_chan;
296 u8 method;
297 u32 passkey = 0;
298 int ret = 0;
299
300 /* Initialize key for JUST WORKS */
301 memset(smp->tk, 0, sizeof(smp->tk));
302 clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
303
304 BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
305
306 /* If neither side wants MITM, use JUST WORKS */
307 /* If either side has unknown io_caps, use JUST WORKS */
308 /* Otherwise, look up method from the table */
309 if (!(auth & SMP_AUTH_MITM) ||
310 local_io > SMP_IO_KEYBOARD_DISPLAY ||
311 remote_io > SMP_IO_KEYBOARD_DISPLAY)
312 method = JUST_WORKS;
313 else
Ido Yarivb3ff53f2012-03-05 20:07:08 +0200314 method = gen_method[remote_io][local_io];
Brian Gix2b64d152011-12-21 16:12:12 -0800315
316 /* If not bonding, don't ask user to confirm a Zero TK */
317 if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
318 method = JUST_WORKS;
319
320 /* If Just Works, Continue with Zero TK */
321 if (method == JUST_WORKS) {
322 set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
323 return 0;
324 }
325
326 /* Not Just Works/Confirm results in MITM Authentication */
327 if (method != JUST_CFM)
328 set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags);
329
330 /* If both devices have Keyoard-Display I/O, the master
331 * Confirms and the slave Enters the passkey.
332 */
333 if (method == OVERLAP) {
334 if (hcon->link_mode & HCI_LM_MASTER)
335 method = CFM_PASSKEY;
336 else
337 method = REQ_PASSKEY;
338 }
339
340 /* Generate random passkey. Not valid until confirmed. */
341 if (method == CFM_PASSKEY) {
342 u8 key[16];
343
344 memset(key, 0, sizeof(key));
345 get_random_bytes(&passkey, sizeof(passkey));
346 passkey %= 1000000;
347 put_unaligned_le32(passkey, key);
348 swap128(key, smp->tk);
349 BT_DBG("PassKey: %d", passkey);
350 }
351
352 hci_dev_lock(hcon->hdev);
353
354 if (method == REQ_PASSKEY)
Johan Hedberg272d90d2012-02-09 15:26:12 +0200355 ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
356 hcon->type, hcon->dst_type);
Brian Gix2b64d152011-12-21 16:12:12 -0800357 else
358 ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
Johan Hedberg272d90d2012-02-09 15:26:12 +0200359 hcon->type, hcon->dst_type,
Brian Gix2b64d152011-12-21 16:12:12 -0800360 cpu_to_le32(passkey), 0);
361
362 hci_dev_unlock(hcon->hdev);
363
364 return ret;
365}
366
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300367static void confirm_work(struct work_struct *work)
368{
369 struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
370 struct l2cap_conn *conn = smp->conn;
371 struct crypto_blkcipher *tfm;
372 struct smp_cmd_pairing_confirm cp;
373 int ret;
374 u8 res[16], reason;
375
376 BT_DBG("conn %p", conn);
377
378 tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
379 if (IS_ERR(tfm)) {
380 reason = SMP_UNSPECIFIED;
381 goto error;
382 }
383
384 smp->tfm = tfm;
385
386 if (conn->hcon->out)
387 ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300388 conn->src, conn->hcon->dst_type, conn->dst, res);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300389 else
390 ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300391 conn->hcon->dst_type, conn->dst, 0, conn->src,
392 res);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300393 if (ret) {
394 reason = SMP_UNSPECIFIED;
395 goto error;
396 }
397
Brian Gix2b64d152011-12-21 16:12:12 -0800398 clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
399
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300400 swap128(res, cp.confirm_val);
401 smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
402
403 return;
404
405error:
Brian Gix4f957a72011-11-23 08:28:36 -0800406 smp_failure(conn, reason, 1);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300407}
408
409static void random_work(struct work_struct *work)
410{
411 struct smp_chan *smp = container_of(work, struct smp_chan, random);
412 struct l2cap_conn *conn = smp->conn;
413 struct hci_conn *hcon = conn->hcon;
414 struct crypto_blkcipher *tfm = smp->tfm;
415 u8 reason, confirm[16], res[16], key[16];
416 int ret;
417
418 if (IS_ERR_OR_NULL(tfm)) {
419 reason = SMP_UNSPECIFIED;
420 goto error;
421 }
422
423 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
424
425 if (hcon->out)
426 ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300427 conn->src, hcon->dst_type, conn->dst, res);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300428 else
429 ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300430 hcon->dst_type, conn->dst, 0, conn->src, res);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300431 if (ret) {
432 reason = SMP_UNSPECIFIED;
433 goto error;
434 }
435
436 swap128(res, confirm);
437
438 if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
439 BT_ERR("Pairing failed (confirmation values mismatch)");
440 reason = SMP_CONFIRM_FAILED;
441 goto error;
442 }
443
444 if (hcon->out) {
445 u8 stk[16], rand[8];
446 __le16 ediv;
447
448 memset(rand, 0, sizeof(rand));
449 ediv = 0;
450
451 smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
452 swap128(key, stk);
453
Vinicius Costa Gomesf7aa6112012-01-30 19:29:12 -0300454 memset(stk + smp->enc_key_size, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300455 SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300456
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200457 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300458 reason = SMP_UNSPECIFIED;
459 goto error;
460 }
461
462 hci_le_start_enc(hcon, ediv, rand, stk);
Vinicius Costa Gomesf7aa6112012-01-30 19:29:12 -0300463 hcon->enc_key_size = smp->enc_key_size;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300464 } else {
465 u8 stk[16], r[16], rand[8];
466 __le16 ediv;
467
468 memset(rand, 0, sizeof(rand));
469 ediv = 0;
470
471 swap128(smp->prnd, r);
472 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
473
474 smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
475 swap128(key, stk);
476
Vinicius Costa Gomesf7aa6112012-01-30 19:29:12 -0300477 memset(stk + smp->enc_key_size, 0,
478 SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300479
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300480 hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300481 HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
482 ediv, rand);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300483 }
484
485 return;
486
487error:
Brian Gix4f957a72011-11-23 08:28:36 -0800488 smp_failure(conn, reason, 1);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300489}
490
491static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
492{
493 struct smp_chan *smp;
494
495 smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
496 if (!smp)
497 return NULL;
498
499 INIT_WORK(&smp->confirm, confirm_work);
500 INIT_WORK(&smp->random, random_work);
501
502 smp->conn = conn;
503 conn->smp_chan = smp;
Brian Gix2b64d152011-12-21 16:12:12 -0800504 conn->hcon->smp_conn = conn;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300505
506 hci_conn_hold(conn->hcon);
507
508 return smp;
509}
510
511void smp_chan_destroy(struct l2cap_conn *conn)
512{
Brian Gixc8eb9692011-11-23 08:28:35 -0800513 struct smp_chan *smp = conn->smp_chan;
514
Vinicius Costa Gomesf1c09c02012-02-01 18:27:56 -0300515 BUG_ON(!smp);
Brian Gixc8eb9692011-11-23 08:28:35 -0800516
517 if (smp->tfm)
518 crypto_free_blkcipher(smp->tfm);
519
520 kfree(smp);
521 conn->smp_chan = NULL;
Brian Gix2b64d152011-12-21 16:12:12 -0800522 conn->hcon->smp_conn = NULL;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300523 hci_conn_put(conn->hcon);
524}
525
Brian Gix2b64d152011-12-21 16:12:12 -0800526int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
527{
528 struct l2cap_conn *conn = hcon->smp_conn;
529 struct smp_chan *smp;
530 u32 value;
531 u8 key[16];
532
533 BT_DBG("");
534
535 if (!conn)
536 return -ENOTCONN;
537
538 smp = conn->smp_chan;
539
540 switch (mgmt_op) {
541 case MGMT_OP_USER_PASSKEY_REPLY:
542 value = le32_to_cpu(passkey);
543 memset(key, 0, sizeof(key));
544 BT_DBG("PassKey: %d", value);
545 put_unaligned_le32(value, key);
546 swap128(key, smp->tk);
547 /* Fall Through */
548 case MGMT_OP_USER_CONFIRM_REPLY:
549 set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
550 break;
551 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
552 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
553 smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
554 return 0;
555 default:
556 smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
557 return -EOPNOTSUPP;
558 }
559
560 /* If it is our turn to send Pairing Confirm, do so now */
561 if (test_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags))
562 queue_work(hcon->hdev->workqueue, &smp->confirm);
563
564 return 0;
565}
566
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300567static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300568{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300569 struct smp_cmd_pairing rsp, *req = (void *) skb->data;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300570 struct smp_chan *smp;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300571 u8 key_size;
Brian Gix2b64d152011-12-21 16:12:12 -0800572 u8 auth = SMP_AUTH_NONE;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300573 int ret;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300574
575 BT_DBG("conn %p", conn);
576
Brian Gix2b64d152011-12-21 16:12:12 -0800577 if (conn->hcon->link_mode & HCI_LM_MASTER)
578 return SMP_CMD_NOTSUPP;
579
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200580 if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300581 smp = smp_chan_create(conn);
Andrei Emeltchenkod08fd0e2012-07-19 17:03:43 +0300582 else
583 smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300584
Andrei Emeltchenkod08fd0e2012-07-19 17:03:43 +0300585 if (!smp)
586 return SMP_UNSPECIFIED;
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300587
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300588 smp->preq[0] = SMP_CMD_PAIRING_REQ;
589 memcpy(&smp->preq[1], req, sizeof(*req));
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300590 skb_pull(skb, sizeof(*req));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300591
Brian Gix2b64d152011-12-21 16:12:12 -0800592 /* We didn't start the pairing, so match remote */
593 if (req->auth_req & SMP_AUTH_BONDING)
594 auth = req->auth_req;
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300595
Ido Yarivfdde0a22012-03-05 20:09:38 +0200596 conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
597
Brian Gix2b64d152011-12-21 16:12:12 -0800598 build_pairing_cmd(conn, req, &rsp, auth);
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300599
600 key_size = min(req->max_key_size, rsp.max_key_size);
601 if (check_enc_key_size(conn, key_size))
602 return SMP_ENC_KEY_SIZE;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300603
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300604 ret = smp_rand(smp->prnd);
605 if (ret)
606 return SMP_UNSPECIFIED;
607
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300608 smp->prsp[0] = SMP_CMD_PAIRING_RSP;
609 memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300610
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300611 smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300612
Brian Gix2b64d152011-12-21 16:12:12 -0800613 /* Request setup of TK */
614 ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
615 if (ret)
616 return SMP_UNSPECIFIED;
617
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300618 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300619}
620
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300621static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300622{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300623 struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300624 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300625 struct hci_dev *hdev = conn->hcon->hdev;
Brian Gix2b64d152011-12-21 16:12:12 -0800626 u8 key_size, auth = SMP_AUTH_NONE;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300627 int ret;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300628
629 BT_DBG("conn %p", conn);
630
Brian Gix2b64d152011-12-21 16:12:12 -0800631 if (!(conn->hcon->link_mode & HCI_LM_MASTER))
632 return SMP_CMD_NOTSUPP;
633
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300634 skb_pull(skb, sizeof(*rsp));
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300635
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300636 req = (void *) &smp->preq[1];
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300637
638 key_size = min(req->max_key_size, rsp->max_key_size);
639 if (check_enc_key_size(conn, key_size))
640 return SMP_ENC_KEY_SIZE;
641
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300642 ret = smp_rand(smp->prnd);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300643 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300644 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300645
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300646 smp->prsp[0] = SMP_CMD_PAIRING_RSP;
647 memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300648
Brian Gix2b64d152011-12-21 16:12:12 -0800649 if ((req->auth_req & SMP_AUTH_BONDING) &&
650 (rsp->auth_req & SMP_AUTH_BONDING))
651 auth = SMP_AUTH_BONDING;
652
653 auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
654
Johan Hedberg476585e2012-06-06 18:54:15 +0800655 ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
Brian Gix2b64d152011-12-21 16:12:12 -0800656 if (ret)
657 return SMP_UNSPECIFIED;
658
659 set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
660
661 /* Can't compose response until we have been confirmed */
662 if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
663 return 0;
664
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300665 queue_work(hdev->workqueue, &smp->confirm);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300666
667 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300668}
669
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300670static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300671{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300672 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300673 struct hci_dev *hdev = conn->hcon->hdev;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300674
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300675 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
676
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300677 memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
678 skb_pull(skb, sizeof(smp->pcnf));
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300679
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300680 if (conn->hcon->out) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300681 u8 random[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300682
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300683 swap128(smp->prnd, random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300684 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300685 random);
Brian Gix2b64d152011-12-21 16:12:12 -0800686 } else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300687 queue_work(hdev->workqueue, &smp->confirm);
Brian Gix2b64d152011-12-21 16:12:12 -0800688 } else {
689 set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300690 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300691
692 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300693}
694
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300695static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300696{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300697 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300698 struct hci_dev *hdev = conn->hcon->hdev;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300699
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300700 BT_DBG("conn %p", conn);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300701
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300702 swap128(skb->data, smp->rrnd);
703 skb_pull(skb, sizeof(smp->rrnd));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300704
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300705 queue_work(hdev->workqueue, &smp->random);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300706
707 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300708}
709
Johan Hedberg4dab7862012-06-07 14:58:37 +0800710static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300711{
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300712 struct smp_ltk *key;
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300713 struct hci_conn *hcon = conn->hcon;
714
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300715 key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type);
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300716 if (!key)
717 return 0;
718
Johan Hedberg4dab7862012-06-07 14:58:37 +0800719 if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
720 return 0;
721
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200722 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300723 return 1;
724
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300725 hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
726 hcon->enc_key_size = key->enc_size;
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300727
728 return 1;
729
730}
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300731static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300732{
733 struct smp_cmd_security_req *rp = (void *) skb->data;
734 struct smp_cmd_pairing cp;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300735 struct hci_conn *hcon = conn->hcon;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300736 struct smp_chan *smp;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300737
738 BT_DBG("conn %p", conn);
739
Brian Gix2b64d152011-12-21 16:12:12 -0800740 hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
Vinicius Costa Gomesfeb45eb2011-08-25 20:02:35 -0300741
Johan Hedberg4dab7862012-06-07 14:58:37 +0800742 if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300743 return 0;
744
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200745 if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300746 return 0;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300747
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300748 smp = smp_chan_create(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300749
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300750 skb_pull(skb, sizeof(*rp));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300751
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300752 memset(&cp, 0, sizeof(cp));
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300753 build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300754
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300755 smp->preq[0] = SMP_CMD_PAIRING_REQ;
756 memcpy(&smp->preq[1], &cp, sizeof(cp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300757
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300758 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300759
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300760 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300761}
762
Vinicius Costa Gomescc110922012-08-23 21:32:43 -0300763int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300764{
Vinicius Costa Gomescc110922012-08-23 21:32:43 -0300765 struct l2cap_conn *conn = hcon->l2cap_data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300766 struct smp_chan *smp = conn->smp_chan;
Brian Gix2b64d152011-12-21 16:12:12 -0800767 __u8 authreq;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300768
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300769 BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
770
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300771 if (!lmp_host_le_capable(hcon->hdev))
772 return 1;
773
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300774 if (sec_level == BT_SECURITY_LOW)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300775 return 1;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300776
777 if (hcon->sec_level >= sec_level)
778 return 1;
779
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300780 if (hcon->link_mode & HCI_LM_MASTER)
Johan Hedberg4dab7862012-06-07 14:58:37 +0800781 if (smp_ltk_encrypt(conn, sec_level))
Vinicius Costa Gomes02bc7452011-07-07 18:59:41 -0300782 goto done;
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300783
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200784 if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300785 return 0;
786
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300787 smp = smp_chan_create(conn);
Brian Gix2b64d152011-12-21 16:12:12 -0800788 if (!smp)
789 return 1;
790
791 authreq = seclevel_to_authreq(sec_level);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300792
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300793 if (hcon->link_mode & HCI_LM_MASTER) {
794 struct smp_cmd_pairing cp;
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300795
Brian Gix2b64d152011-12-21 16:12:12 -0800796 build_pairing_cmd(conn, &cp, NULL, authreq);
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300797 smp->preq[0] = SMP_CMD_PAIRING_REQ;
798 memcpy(&smp->preq[1], &cp, sizeof(cp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300799
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300800 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
801 } else {
802 struct smp_cmd_security_req cp;
Brian Gix2b64d152011-12-21 16:12:12 -0800803 cp.auth_req = authreq;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300804 smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
805 }
806
Vinicius Costa Gomes02bc7452011-07-07 18:59:41 -0300807done:
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300808 hcon->pending_sec_level = sec_level;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300809
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300810 return 0;
811}
812
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300813static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
814{
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300815 struct smp_cmd_encrypt_info *rp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300816 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300817
818 skb_pull(skb, sizeof(*rp));
819
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300820 memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300821
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300822 return 0;
823}
824
825static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
826{
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300827 struct smp_cmd_master_ident *rp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300828 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300829 struct hci_dev *hdev = conn->hcon->hdev;
830 struct hci_conn *hcon = conn->hcon;
831 u8 authenticated;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300832
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300833 skb_pull(skb, sizeof(*rp));
834
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300835 hci_dev_lock(hdev);
836 authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
837 hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300838 HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size,
839 rp->ediv, rp->rand);
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300840 smp_distribute_keys(conn, 1);
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300841 hci_dev_unlock(hdev);
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300842
843 return 0;
844}
845
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300846int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
847{
848 __u8 code = skb->data[0];
849 __u8 reason;
850 int err = 0;
851
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300852 if (!lmp_host_le_capable(conn->hcon->hdev)) {
853 err = -ENOTSUPP;
854 reason = SMP_PAIRING_NOTSUPP;
855 goto done;
856 }
857
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300858 skb_pull(skb, sizeof(code));
859
860 switch (code) {
861 case SMP_CMD_PAIRING_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300862 reason = smp_cmd_pairing_req(conn, skb);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300863 break;
864
865 case SMP_CMD_PAIRING_FAIL:
Brian Gix4f957a72011-11-23 08:28:36 -0800866 smp_failure(conn, skb->data[0], 0);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300867 reason = 0;
868 err = -EPERM;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300869 break;
870
871 case SMP_CMD_PAIRING_RSP:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300872 reason = smp_cmd_pairing_rsp(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300873 break;
874
875 case SMP_CMD_SECURITY_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300876 reason = smp_cmd_security_req(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300877 break;
878
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300879 case SMP_CMD_PAIRING_CONFIRM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300880 reason = smp_cmd_pairing_confirm(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300881 break;
882
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300883 case SMP_CMD_PAIRING_RANDOM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300884 reason = smp_cmd_pairing_random(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300885 break;
886
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300887 case SMP_CMD_ENCRYPT_INFO:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300888 reason = smp_cmd_encrypt_info(conn, skb);
889 break;
890
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300891 case SMP_CMD_MASTER_IDENT:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300892 reason = smp_cmd_master_ident(conn, skb);
893 break;
894
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300895 case SMP_CMD_IDENT_INFO:
896 case SMP_CMD_IDENT_ADDR_INFO:
897 case SMP_CMD_SIGN_INFO:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300898 /* Just ignored */
899 reason = 0;
900 break;
901
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300902 default:
903 BT_DBG("Unknown command code 0x%2.2x", code);
904
905 reason = SMP_CMD_NOTSUPP;
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300906 err = -EOPNOTSUPP;
907 goto done;
908 }
909
910done:
911 if (reason)
Brian Gix4f957a72011-11-23 08:28:36 -0800912 smp_failure(conn, reason, 1);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300913
914 kfree_skb(skb);
915 return err;
916}
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300917
918int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
919{
920 struct smp_cmd_pairing *req, *rsp;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300921 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300922 __u8 *keydist;
923
924 BT_DBG("conn %p force %d", conn, force);
925
Johan Hedberg51a8efd2012-01-16 06:10:31 +0200926 if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300927 return 0;
928
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300929 rsp = (void *) &smp->prsp[1];
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300930
931 /* The responder sends its keys first */
932 if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
933 return 0;
934
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300935 req = (void *) &smp->preq[1];
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300936
937 if (conn->hcon->out) {
938 keydist = &rsp->init_key_dist;
939 *keydist &= req->init_key_dist;
940 } else {
941 keydist = &rsp->resp_key_dist;
942 *keydist &= req->resp_key_dist;
943 }
944
945
946 BT_DBG("keydist 0x%x", *keydist);
947
948 if (*keydist & SMP_DIST_ENC_KEY) {
949 struct smp_cmd_encrypt_info enc;
950 struct smp_cmd_master_ident ident;
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300951 struct hci_conn *hcon = conn->hcon;
952 u8 authenticated;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300953 __le16 ediv;
954
955 get_random_bytes(enc.ltk, sizeof(enc.ltk));
956 get_random_bytes(&ediv, sizeof(ediv));
957 get_random_bytes(ident.rand, sizeof(ident.rand));
958
959 smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
960
Vinicius Costa Gomesc9839a12012-02-02 21:08:01 -0300961 authenticated = hcon->sec_level == BT_SECURITY_HIGH;
962 hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300963 HCI_SMP_LTK_SLAVE, 1, authenticated,
964 enc.ltk, smp->enc_key_size, ediv, ident.rand);
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300965
Andrei Emeltchenko58115372012-03-12 12:13:06 +0200966 ident.ediv = ediv;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300967
968 smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
969
970 *keydist &= ~SMP_DIST_ENC_KEY;
971 }
972
973 if (*keydist & SMP_DIST_ID_KEY) {
974 struct smp_cmd_ident_addr_info addrinfo;
975 struct smp_cmd_ident_info idinfo;
976
977 /* Send a dummy key */
978 get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
979
980 smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
981
982 /* Just public address */
983 memset(&addrinfo, 0, sizeof(addrinfo));
984 bacpy(&addrinfo.bdaddr, conn->src);
985
986 smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
987 &addrinfo);
988
989 *keydist &= ~SMP_DIST_ID_KEY;
990 }
991
992 if (*keydist & SMP_DIST_SIGN) {
993 struct smp_cmd_sign_info sign;
994
995 /* Send a dummy key */
996 get_random_bytes(sign.csrk, sizeof(sign.csrk));
997
998 smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
999
1000 *keydist &= ~SMP_DIST_SIGN;
1001 }
1002
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001003 if (conn->hcon->out || force) {
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001004 clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001005 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001006 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001007 }
1008
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -03001009 return 0;
1010}