blob: ba55bd4b5dda6b2a84f728083285a56e00b6f6ee [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
23#include <net/bluetooth/bluetooth.h>
24#include <net/bluetooth/hci_core.h>
25#include <net/bluetooth/l2cap.h>
26#include <net/bluetooth/smp.h>
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030027#include <linux/crypto.h>
Stephen Rothwellf70490e2011-06-23 12:58:55 +100028#include <linux/scatterlist.h>
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030029#include <crypto/b128ops.h>
30
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -030031#define SMP_TIMEOUT 30000 /* 30 seconds */
32
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030033static inline void swap128(u8 src[16], u8 dst[16])
34{
35 int i;
36 for (i = 0; i < 16; i++)
37 dst[15 - i] = src[i];
38}
39
40static inline void swap56(u8 src[7], u8 dst[7])
41{
42 int i;
43 for (i = 0; i < 7; i++)
44 dst[6 - i] = src[i];
45}
46
47static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
48{
49 struct blkcipher_desc desc;
50 struct scatterlist sg;
51 int err, iv_len;
52 unsigned char iv[128];
53
54 if (tfm == NULL) {
55 BT_ERR("tfm %p", tfm);
56 return -EINVAL;
57 }
58
59 desc.tfm = tfm;
60 desc.flags = 0;
61
62 err = crypto_blkcipher_setkey(tfm, k, 16);
63 if (err) {
64 BT_ERR("cipher setkey failed: %d", err);
65 return err;
66 }
67
68 sg_init_one(&sg, r, 16);
69
70 iv_len = crypto_blkcipher_ivsize(tfm);
71 if (iv_len) {
72 memset(&iv, 0xff, iv_len);
73 crypto_blkcipher_set_iv(tfm, iv, iv_len);
74 }
75
76 err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
77 if (err)
78 BT_ERR("Encrypt data error %d", err);
79
80 return err;
81}
82
83static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
84 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
85 u8 _rat, bdaddr_t *ra, u8 res[16])
86{
87 u8 p1[16], p2[16];
88 int err;
89
90 memset(p1, 0, 16);
91
92 /* p1 = pres || preq || _rat || _iat */
93 swap56(pres, p1);
94 swap56(preq, p1 + 7);
95 p1[14] = _rat;
96 p1[15] = _iat;
97
98 memset(p2, 0, 16);
99
100 /* p2 = padding || ia || ra */
101 baswap((bdaddr_t *) (p2 + 4), ia);
102 baswap((bdaddr_t *) (p2 + 10), ra);
103
104 /* res = r XOR p1 */
105 u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
106
107 /* res = e(k, res) */
108 err = smp_e(tfm, k, res);
109 if (err) {
110 BT_ERR("Encrypt data error");
111 return err;
112 }
113
114 /* res = res XOR p2 */
115 u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
116
117 /* res = e(k, res) */
118 err = smp_e(tfm, k, res);
119 if (err)
120 BT_ERR("Encrypt data error");
121
122 return err;
123}
124
125static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
126 u8 r1[16], u8 r2[16], u8 _r[16])
127{
128 int err;
129
130 /* Just least significant octets from r1 and r2 are considered */
131 memcpy(_r, r1 + 8, 8);
132 memcpy(_r + 8, r2 + 8, 8);
133
134 err = smp_e(tfm, k, _r);
135 if (err)
136 BT_ERR("Encrypt data error");
137
138 return err;
139}
140
141static int smp_rand(u8 *buf)
142{
143 get_random_bytes(buf, 16);
144
145 return 0;
146}
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300147
148static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
149 u16 dlen, void *data)
150{
151 struct sk_buff *skb;
152 struct l2cap_hdr *lh;
153 int len;
154
155 len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
156
157 if (len > conn->mtu)
158 return NULL;
159
160 skb = bt_skb_alloc(len, GFP_ATOMIC);
161 if (!skb)
162 return NULL;
163
164 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
165 lh->len = cpu_to_le16(sizeof(code) + dlen);
166 lh->cid = cpu_to_le16(L2CAP_CID_SMP);
167
168 memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
169
170 memcpy(skb_put(skb, dlen), data, dlen);
171
172 return skb;
173}
174
175static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
176{
177 struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
178
179 BT_DBG("code 0x%2.2x", code);
180
181 if (!skb)
182 return;
183
184 hci_send_acl(conn->hcon, skb, 0);
185}
186
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300187static __u8 seclevel_to_authreq(__u8 level)
188{
189 switch (level) {
190 case BT_SECURITY_HIGH:
191 /* Right now we don't support bonding */
192 return SMP_AUTH_MITM;
193
194 default:
195 return SMP_AUTH_NONE;
196 }
197}
198
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300199static void build_pairing_cmd(struct l2cap_conn *conn,
200 struct smp_cmd_pairing *cmd, __u8 authreq)
201{
202 cmd->io_capability = conn->hcon->io_capability;
203 cmd->oob_flag = SMP_OOB_NOT_PRESENT;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300204 cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300205 cmd->init_key_dist = 0x00;
206 cmd->resp_key_dist = 0x00;
207 cmd->auth_req = authreq;
208}
209
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300210static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
211{
212 if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
213 (max_key_size < SMP_MIN_ENC_KEY_SIZE))
214 return SMP_ENC_KEY_SIZE;
215
216 conn->smp_key_size = max_key_size;
217
218 return 0;
219}
220
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300221static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300222{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300223 struct smp_cmd_pairing rsp, *req = (void *) skb->data;
224 u8 key_size;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300225
226 BT_DBG("conn %p", conn);
227
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300228 conn->preq[0] = SMP_CMD_PAIRING_REQ;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300229 memcpy(&conn->preq[1], req, sizeof(*req));
230 skb_pull(skb, sizeof(*req));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300231
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300232 if (req->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300233 return SMP_OOB_NOT_AVAIL;
234
235 /* We didn't start the pairing, so no requirements */
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300236 build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
237
238 key_size = min(req->max_key_size, rsp.max_key_size);
239 if (check_enc_key_size(conn, key_size))
240 return SMP_ENC_KEY_SIZE;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300241
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300242 /* Just works */
243 memset(conn->tk, 0, sizeof(conn->tk));
244
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300245 conn->prsp[0] = SMP_CMD_PAIRING_RSP;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300246 memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300247
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300248 smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300249
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300250 mod_timer(&conn->security_timer, jiffies +
251 msecs_to_jiffies(SMP_TIMEOUT));
252
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300253 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300254}
255
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300256static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300257{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300258 struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300259 struct smp_cmd_pairing_confirm cp;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300260 struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
261 int ret;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300262 u8 res[16], key_size;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300263
264 BT_DBG("conn %p", conn);
265
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300266 skb_pull(skb, sizeof(*rsp));
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300267
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300268 req = (void *) &conn->preq[1];
269
270 key_size = min(req->max_key_size, rsp->max_key_size);
271 if (check_enc_key_size(conn, key_size))
272 return SMP_ENC_KEY_SIZE;
273
274 if (rsp->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300275 return SMP_OOB_NOT_AVAIL;
276
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300277 /* Just works */
278 memset(conn->tk, 0, sizeof(conn->tk));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300279
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300280 conn->prsp[0] = SMP_CMD_PAIRING_RSP;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300281 memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300282
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300283 ret = smp_rand(conn->prnd);
284 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300285 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300286
287 ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
288 conn->src, conn->hcon->dst_type, conn->dst, res);
289 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300290 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300291
292 swap128(res, cp.confirm_val);
293
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300294 smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300295
296 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300297}
298
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300299static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300300{
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300301 struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
302
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300303 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
304
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300305 memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
306 skb_pull(skb, sizeof(conn->pcnf));
307
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300308 if (conn->hcon->out) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300309 u8 random[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300310
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300311 swap128(conn->prnd, random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300312 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300313 random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300314 } else {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300315 struct smp_cmd_pairing_confirm cp;
316 int ret;
317 u8 res[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300318
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300319 ret = smp_rand(conn->prnd);
320 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300321 return SMP_UNSPECIFIED;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300322
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300323 ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
324 conn->hcon->dst_type, conn->dst,
325 0, conn->src, res);
326 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300327 return SMP_CONFIRM_FAILED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300328
329 swap128(res, cp.confirm_val);
330
331 smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300332 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300333
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300334 mod_timer(&conn->security_timer, jiffies +
335 msecs_to_jiffies(SMP_TIMEOUT));
336
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300337 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300338}
339
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300340static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300341{
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300342 struct hci_conn *hcon = conn->hcon;
343 struct crypto_blkcipher *tfm = hcon->hdev->tfm;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300344 int ret;
Vinicius Costa Gomes9b3d6742011-06-09 18:50:48 -0300345 u8 key[16], res[16], random[16], confirm[16];
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300346
347 swap128(skb->data, random);
348 skb_pull(skb, sizeof(random));
349
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300350 memset(hcon->ltk, 0, sizeof(hcon->ltk));
351
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300352 if (conn->hcon->out)
353 ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
354 conn->src, conn->hcon->dst_type, conn->dst,
355 res);
356 else
357 ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
358 conn->hcon->dst_type, conn->dst, 0, conn->src,
359 res);
360 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300361 return SMP_UNSPECIFIED;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300362
363 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
364
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300365 swap128(res, confirm);
366
367 if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300368 BT_ERR("Pairing failed (confirmation values mismatch)");
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300369 return SMP_CONFIRM_FAILED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300370 }
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300371
372 if (conn->hcon->out) {
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300373 __le16 ediv;
374 u8 rand[8];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300375
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300376 smp_s1(tfm, conn->tk, random, conn->prnd, key);
377 swap128(key, hcon->ltk);
378
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300379 memset(hcon->ltk + conn->smp_key_size, 0,
380 SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
381
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300382 memset(rand, 0, sizeof(rand));
383 ediv = 0;
384 hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300385 } else {
386 u8 r[16];
387
388 swap128(conn->prnd, r);
389 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
390
391 smp_s1(tfm, conn->tk, conn->prnd, random, key);
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300392 swap128(key, hcon->ltk);
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300393
394 memset(hcon->ltk + conn->smp_key_size, 0,
395 SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300396 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300397
398 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300399}
400
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300401static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300402{
403 struct smp_cmd_security_req *rp = (void *) skb->data;
404 struct smp_cmd_pairing cp;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300405 struct hci_conn *hcon = conn->hcon;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300406
407 BT_DBG("conn %p", conn);
408
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300409 if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300410 return 0;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300411
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300412 skb_pull(skb, sizeof(*rp));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300413
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300414 memset(&cp, 0, sizeof(cp));
415 build_pairing_cmd(conn, &cp, rp->auth_req);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300416
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300417 conn->preq[0] = SMP_CMD_PAIRING_REQ;
418 memcpy(&conn->preq[1], &cp, sizeof(cp));
419
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300420 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300421
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300422 mod_timer(&conn->security_timer, jiffies +
423 msecs_to_jiffies(SMP_TIMEOUT));
424
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300425 set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300426
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300427 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300428}
429
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300430int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
431{
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300432 struct hci_conn *hcon = conn->hcon;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300433 __u8 authreq;
434
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300435 BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
436
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300437 if (!lmp_host_le_capable(hcon->hdev))
438 return 1;
439
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300440 if (IS_ERR(hcon->hdev->tfm))
441 return 1;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300442
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300443 if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
444 return 0;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300445
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300446 if (sec_level == BT_SECURITY_LOW)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300447 return 1;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300448
449 if (hcon->sec_level >= sec_level)
450 return 1;
451
452 authreq = seclevel_to_authreq(sec_level);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300453
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300454 if (hcon->link_mode & HCI_LM_MASTER) {
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300455 struct smp_cmd_pairing cp;
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300456
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300457 build_pairing_cmd(conn, &cp, authreq);
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300458 conn->preq[0] = SMP_CMD_PAIRING_REQ;
459 memcpy(&conn->preq[1], &cp, sizeof(cp));
460
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300461 mod_timer(&conn->security_timer, jiffies +
462 msecs_to_jiffies(SMP_TIMEOUT));
463
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300464 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
465 } else {
466 struct smp_cmd_security_req cp;
467 cp.auth_req = authreq;
468 smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
469 }
470
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300471 hcon->pending_sec_level = sec_level;
472 set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
473
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300474 return 0;
475}
476
477int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
478{
479 __u8 code = skb->data[0];
480 __u8 reason;
481 int err = 0;
482
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300483 if (!lmp_host_le_capable(conn->hcon->hdev)) {
484 err = -ENOTSUPP;
485 reason = SMP_PAIRING_NOTSUPP;
486 goto done;
487 }
488
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300489 if (IS_ERR(conn->hcon->hdev->tfm)) {
490 err = PTR_ERR(conn->hcon->hdev->tfm);
491 reason = SMP_PAIRING_NOTSUPP;
492 goto done;
493 }
494
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300495 skb_pull(skb, sizeof(code));
496
497 switch (code) {
498 case SMP_CMD_PAIRING_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300499 reason = smp_cmd_pairing_req(conn, skb);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300500 break;
501
502 case SMP_CMD_PAIRING_FAIL:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300503 reason = 0;
504 err = -EPERM;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300505 break;
506
507 case SMP_CMD_PAIRING_RSP:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300508 reason = smp_cmd_pairing_rsp(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300509 break;
510
511 case SMP_CMD_SECURITY_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300512 reason = smp_cmd_security_req(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300513 break;
514
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300515 case SMP_CMD_PAIRING_CONFIRM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300516 reason = smp_cmd_pairing_confirm(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300517 break;
518
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300519 case SMP_CMD_PAIRING_RANDOM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300520 reason = smp_cmd_pairing_random(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300521 break;
522
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300523 case SMP_CMD_ENCRYPT_INFO:
524 case SMP_CMD_MASTER_IDENT:
525 case SMP_CMD_IDENT_INFO:
526 case SMP_CMD_IDENT_ADDR_INFO:
527 case SMP_CMD_SIGN_INFO:
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300528 default:
529 BT_DBG("Unknown command code 0x%2.2x", code);
530
531 reason = SMP_CMD_NOTSUPP;
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300532 err = -EOPNOTSUPP;
533 goto done;
534 }
535
536done:
537 if (reason)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300538 smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
539 &reason);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300540
541 kfree_skb(skb);
542 return err;
543}