blob: 52e9ec2644c10445fed7804d85e4581ac913cc2f [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>
28#include <crypto/b128ops.h>
29
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -030030#define SMP_TIMEOUT 30000 /* 30 seconds */
31
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030032static inline void swap128(u8 src[16], u8 dst[16])
33{
34 int i;
35 for (i = 0; i < 16; i++)
36 dst[15 - i] = src[i];
37}
38
39static inline void swap56(u8 src[7], u8 dst[7])
40{
41 int i;
42 for (i = 0; i < 7; i++)
43 dst[6 - i] = src[i];
44}
45
46static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
47{
48 struct blkcipher_desc desc;
49 struct scatterlist sg;
50 int err, iv_len;
51 unsigned char iv[128];
52
53 if (tfm == NULL) {
54 BT_ERR("tfm %p", tfm);
55 return -EINVAL;
56 }
57
58 desc.tfm = tfm;
59 desc.flags = 0;
60
61 err = crypto_blkcipher_setkey(tfm, k, 16);
62 if (err) {
63 BT_ERR("cipher setkey failed: %d", err);
64 return err;
65 }
66
67 sg_init_one(&sg, r, 16);
68
69 iv_len = crypto_blkcipher_ivsize(tfm);
70 if (iv_len) {
71 memset(&iv, 0xff, iv_len);
72 crypto_blkcipher_set_iv(tfm, iv, iv_len);
73 }
74
75 err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
76 if (err)
77 BT_ERR("Encrypt data error %d", err);
78
79 return err;
80}
81
82static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
83 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
84 u8 _rat, bdaddr_t *ra, u8 res[16])
85{
86 u8 p1[16], p2[16];
87 int err;
88
89 memset(p1, 0, 16);
90
91 /* p1 = pres || preq || _rat || _iat */
92 swap56(pres, p1);
93 swap56(preq, p1 + 7);
94 p1[14] = _rat;
95 p1[15] = _iat;
96
97 memset(p2, 0, 16);
98
99 /* p2 = padding || ia || ra */
100 baswap((bdaddr_t *) (p2 + 4), ia);
101 baswap((bdaddr_t *) (p2 + 10), ra);
102
103 /* res = r XOR p1 */
104 u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
105
106 /* res = e(k, res) */
107 err = smp_e(tfm, k, res);
108 if (err) {
109 BT_ERR("Encrypt data error");
110 return err;
111 }
112
113 /* res = res XOR p2 */
114 u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
115
116 /* res = e(k, res) */
117 err = smp_e(tfm, k, res);
118 if (err)
119 BT_ERR("Encrypt data error");
120
121 return err;
122}
123
124static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
125 u8 r1[16], u8 r2[16], u8 _r[16])
126{
127 int err;
128
129 /* Just least significant octets from r1 and r2 are considered */
130 memcpy(_r, r1 + 8, 8);
131 memcpy(_r + 8, r2 + 8, 8);
132
133 err = smp_e(tfm, k, _r);
134 if (err)
135 BT_ERR("Encrypt data error");
136
137 return err;
138}
139
140static int smp_rand(u8 *buf)
141{
142 get_random_bytes(buf, 16);
143
144 return 0;
145}
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300146
147static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
148 u16 dlen, void *data)
149{
150 struct sk_buff *skb;
151 struct l2cap_hdr *lh;
152 int len;
153
154 len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
155
156 if (len > conn->mtu)
157 return NULL;
158
159 skb = bt_skb_alloc(len, GFP_ATOMIC);
160 if (!skb)
161 return NULL;
162
163 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
164 lh->len = cpu_to_le16(sizeof(code) + dlen);
165 lh->cid = cpu_to_le16(L2CAP_CID_SMP);
166
167 memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
168
169 memcpy(skb_put(skb, dlen), data, dlen);
170
171 return skb;
172}
173
174static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
175{
176 struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
177
178 BT_DBG("code 0x%2.2x", code);
179
180 if (!skb)
181 return;
182
183 hci_send_acl(conn->hcon, skb, 0);
184}
185
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300186static __u8 seclevel_to_authreq(__u8 level)
187{
188 switch (level) {
189 case BT_SECURITY_HIGH:
190 /* Right now we don't support bonding */
191 return SMP_AUTH_MITM;
192
193 default:
194 return SMP_AUTH_NONE;
195 }
196}
197
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300198static void build_pairing_cmd(struct l2cap_conn *conn,
199 struct smp_cmd_pairing *cmd, __u8 authreq)
200{
201 cmd->io_capability = conn->hcon->io_capability;
202 cmd->oob_flag = SMP_OOB_NOT_PRESENT;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300203 cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300204 cmd->init_key_dist = 0x00;
205 cmd->resp_key_dist = 0x00;
206 cmd->auth_req = authreq;
207}
208
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300209static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
210{
211 if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
212 (max_key_size < SMP_MIN_ENC_KEY_SIZE))
213 return SMP_ENC_KEY_SIZE;
214
215 conn->smp_key_size = max_key_size;
216
217 return 0;
218}
219
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300220static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300221{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300222 struct smp_cmd_pairing rsp, *req = (void *) skb->data;
223 u8 key_size;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300224
225 BT_DBG("conn %p", conn);
226
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300227 conn->preq[0] = SMP_CMD_PAIRING_REQ;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300228 memcpy(&conn->preq[1], req, sizeof(*req));
229 skb_pull(skb, sizeof(*req));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300230
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300231 if (req->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300232 return SMP_OOB_NOT_AVAIL;
233
234 /* We didn't start the pairing, so no requirements */
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300235 build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
236
237 key_size = min(req->max_key_size, rsp.max_key_size);
238 if (check_enc_key_size(conn, key_size))
239 return SMP_ENC_KEY_SIZE;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300240
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300241 /* Just works */
242 memset(conn->tk, 0, sizeof(conn->tk));
243
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300244 conn->prsp[0] = SMP_CMD_PAIRING_RSP;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300245 memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300246
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300247 smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300248
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300249 mod_timer(&conn->security_timer, jiffies +
250 msecs_to_jiffies(SMP_TIMEOUT));
251
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300252 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300253}
254
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300255static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300256{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300257 struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300258 struct smp_cmd_pairing_confirm cp;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300259 struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
260 int ret;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300261 u8 res[16], key_size;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300262
263 BT_DBG("conn %p", conn);
264
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300265 skb_pull(skb, sizeof(*rsp));
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300266
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300267 req = (void *) &conn->preq[1];
268
269 key_size = min(req->max_key_size, rsp->max_key_size);
270 if (check_enc_key_size(conn, key_size))
271 return SMP_ENC_KEY_SIZE;
272
273 if (rsp->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300274 return SMP_OOB_NOT_AVAIL;
275
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300276 /* Just works */
277 memset(conn->tk, 0, sizeof(conn->tk));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300278
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300279 conn->prsp[0] = SMP_CMD_PAIRING_RSP;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300280 memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300281
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300282 ret = smp_rand(conn->prnd);
283 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300284 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300285
286 ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
287 conn->src, conn->hcon->dst_type, conn->dst, res);
288 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300289 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300290
291 swap128(res, cp.confirm_val);
292
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300293 smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300294
295 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300296}
297
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300298static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300299{
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300300 struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
301
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300302 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
303
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300304 memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
305 skb_pull(skb, sizeof(conn->pcnf));
306
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300307 if (conn->hcon->out) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300308 u8 random[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300309
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300310 swap128(conn->prnd, random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300311 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300312 random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300313 } else {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300314 struct smp_cmd_pairing_confirm cp;
315 int ret;
316 u8 res[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300317
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300318 ret = smp_rand(conn->prnd);
319 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300320 return SMP_UNSPECIFIED;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300321
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300322 ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
323 conn->hcon->dst_type, conn->dst,
324 0, conn->src, res);
325 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300326 return SMP_CONFIRM_FAILED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300327
328 swap128(res, cp.confirm_val);
329
330 smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300331 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300332
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300333 mod_timer(&conn->security_timer, jiffies +
334 msecs_to_jiffies(SMP_TIMEOUT));
335
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300336 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300337}
338
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300339static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300340{
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300341 struct hci_conn *hcon = conn->hcon;
342 struct crypto_blkcipher *tfm = hcon->hdev->tfm;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300343 int ret;
Vinicius Costa Gomes9b3d6742011-06-09 18:50:48 -0300344 u8 key[16], res[16], random[16], confirm[16];
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300345
346 swap128(skb->data, random);
347 skb_pull(skb, sizeof(random));
348
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300349 memset(hcon->ltk, 0, sizeof(hcon->ltk));
350
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300351 if (conn->hcon->out)
352 ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
353 conn->src, conn->hcon->dst_type, conn->dst,
354 res);
355 else
356 ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
357 conn->hcon->dst_type, conn->dst, 0, conn->src,
358 res);
359 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300360 return SMP_UNSPECIFIED;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300361
362 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
363
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300364 swap128(res, confirm);
365
366 if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300367 BT_ERR("Pairing failed (confirmation values mismatch)");
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300368 return SMP_CONFIRM_FAILED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300369 }
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300370
371 if (conn->hcon->out) {
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300372 __le16 ediv;
373 u8 rand[8];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300374
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300375 smp_s1(tfm, conn->tk, random, conn->prnd, key);
376 swap128(key, hcon->ltk);
377
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300378 memset(hcon->ltk + conn->smp_key_size, 0,
379 SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
380
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300381 memset(rand, 0, sizeof(rand));
382 ediv = 0;
383 hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300384 } else {
385 u8 r[16];
386
387 swap128(conn->prnd, r);
388 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
389
390 smp_s1(tfm, conn->tk, conn->prnd, random, key);
Vinicius Costa Gomesa7a595f2011-06-09 18:50:47 -0300391 swap128(key, hcon->ltk);
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300392
393 memset(hcon->ltk + conn->smp_key_size, 0,
394 SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300395 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300396
397 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300398}
399
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300400static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300401{
402 struct smp_cmd_security_req *rp = (void *) skb->data;
403 struct smp_cmd_pairing cp;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300404 struct hci_conn *hcon = conn->hcon;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300405
406 BT_DBG("conn %p", conn);
407
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300408 if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300409 return 0;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300410
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300411 skb_pull(skb, sizeof(*rp));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300412
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300413 memset(&cp, 0, sizeof(cp));
414 build_pairing_cmd(conn, &cp, rp->auth_req);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300415
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300416 conn->preq[0] = SMP_CMD_PAIRING_REQ;
417 memcpy(&conn->preq[1], &cp, sizeof(cp));
418
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300419 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300420
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300421 mod_timer(&conn->security_timer, jiffies +
422 msecs_to_jiffies(SMP_TIMEOUT));
423
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300424 set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300425
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300426 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300427}
428
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300429int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
430{
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300431 struct hci_conn *hcon = conn->hcon;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300432 __u8 authreq;
433
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300434 BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
435
436 if (IS_ERR(hcon->hdev->tfm))
437 return 1;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300438
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300439 if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
440 return 0;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300441
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300442 if (sec_level == BT_SECURITY_LOW)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300443 return 1;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300444
445 if (hcon->sec_level >= sec_level)
446 return 1;
447
448 authreq = seclevel_to_authreq(sec_level);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300449
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300450 if (hcon->link_mode & HCI_LM_MASTER) {
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300451 struct smp_cmd_pairing cp;
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300452
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300453 build_pairing_cmd(conn, &cp, authreq);
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300454 conn->preq[0] = SMP_CMD_PAIRING_REQ;
455 memcpy(&conn->preq[1], &cp, sizeof(cp));
456
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300457 mod_timer(&conn->security_timer, jiffies +
458 msecs_to_jiffies(SMP_TIMEOUT));
459
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300460 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
461 } else {
462 struct smp_cmd_security_req cp;
463 cp.auth_req = authreq;
464 smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
465 }
466
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300467 hcon->pending_sec_level = sec_level;
468 set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
469
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300470 return 0;
471}
472
473int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
474{
475 __u8 code = skb->data[0];
476 __u8 reason;
477 int err = 0;
478
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300479 if (IS_ERR(conn->hcon->hdev->tfm)) {
480 err = PTR_ERR(conn->hcon->hdev->tfm);
481 reason = SMP_PAIRING_NOTSUPP;
482 goto done;
483 }
484
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300485 skb_pull(skb, sizeof(code));
486
487 switch (code) {
488 case SMP_CMD_PAIRING_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300489 reason = smp_cmd_pairing_req(conn, skb);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300490 break;
491
492 case SMP_CMD_PAIRING_FAIL:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300493 reason = 0;
494 err = -EPERM;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300495 break;
496
497 case SMP_CMD_PAIRING_RSP:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300498 reason = smp_cmd_pairing_rsp(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300499 break;
500
501 case SMP_CMD_SECURITY_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300502 reason = smp_cmd_security_req(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300503 break;
504
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300505 case SMP_CMD_PAIRING_CONFIRM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300506 reason = smp_cmd_pairing_confirm(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300507 break;
508
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300509 case SMP_CMD_PAIRING_RANDOM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300510 reason = smp_cmd_pairing_random(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300511 break;
512
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300513 case SMP_CMD_ENCRYPT_INFO:
514 case SMP_CMD_MASTER_IDENT:
515 case SMP_CMD_IDENT_INFO:
516 case SMP_CMD_IDENT_ADDR_INFO:
517 case SMP_CMD_SIGN_INFO:
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300518 default:
519 BT_DBG("Unknown command code 0x%2.2x", code);
520
521 reason = SMP_CMD_NOTSUPP;
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300522 err = -EOPNOTSUPP;
523 goto done;
524 }
525
526done:
527 if (reason)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300528 smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
529 &reason);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300530
531 kfree_skb(skb);
532 return err;
533}