xref: /openbmc/linux/net/bluetooth/smp.c (revision a8b2d5c2)
1eb492e01SAnderson Briglia /*
2eb492e01SAnderson Briglia    BlueZ - Bluetooth protocol stack for Linux
3eb492e01SAnderson Briglia    Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4eb492e01SAnderson Briglia 
5eb492e01SAnderson Briglia    This program is free software; you can redistribute it and/or modify
6eb492e01SAnderson Briglia    it under the terms of the GNU General Public License version 2 as
7eb492e01SAnderson Briglia    published by the Free Software Foundation;
8eb492e01SAnderson Briglia 
9eb492e01SAnderson Briglia    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10eb492e01SAnderson Briglia    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11eb492e01SAnderson Briglia    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12eb492e01SAnderson Briglia    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13eb492e01SAnderson Briglia    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14eb492e01SAnderson Briglia    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15eb492e01SAnderson Briglia    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16eb492e01SAnderson Briglia    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17eb492e01SAnderson Briglia 
18eb492e01SAnderson Briglia    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19eb492e01SAnderson Briglia    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20eb492e01SAnderson Briglia    SOFTWARE IS DISCLAIMED.
21eb492e01SAnderson Briglia */
22eb492e01SAnderson Briglia 
23eb492e01SAnderson Briglia #include <net/bluetooth/bluetooth.h>
24eb492e01SAnderson Briglia #include <net/bluetooth/hci_core.h>
25eb492e01SAnderson Briglia #include <net/bluetooth/l2cap.h>
262b64d153SBrian Gix #include <net/bluetooth/mgmt.h>
27eb492e01SAnderson Briglia #include <net/bluetooth/smp.h>
28d22ef0bcSAnderson Briglia #include <linux/crypto.h>
29f70490e6SStephen Rothwell #include <linux/scatterlist.h>
30d22ef0bcSAnderson Briglia #include <crypto/b128ops.h>
31d22ef0bcSAnderson Briglia 
325d3de7dfSVinicius Costa Gomes #define SMP_TIMEOUT 30000 /* 30 seconds */
335d3de7dfSVinicius Costa Gomes 
34d22ef0bcSAnderson Briglia static inline void swap128(u8 src[16], u8 dst[16])
35d22ef0bcSAnderson Briglia {
36d22ef0bcSAnderson Briglia 	int i;
37d22ef0bcSAnderson Briglia 	for (i = 0; i < 16; i++)
38d22ef0bcSAnderson Briglia 		dst[15 - i] = src[i];
39d22ef0bcSAnderson Briglia }
40d22ef0bcSAnderson Briglia 
41d22ef0bcSAnderson Briglia static inline void swap56(u8 src[7], u8 dst[7])
42d22ef0bcSAnderson Briglia {
43d22ef0bcSAnderson Briglia 	int i;
44d22ef0bcSAnderson Briglia 	for (i = 0; i < 7; i++)
45d22ef0bcSAnderson Briglia 		dst[6 - i] = src[i];
46d22ef0bcSAnderson Briglia }
47d22ef0bcSAnderson Briglia 
48d22ef0bcSAnderson Briglia static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
49d22ef0bcSAnderson Briglia {
50d22ef0bcSAnderson Briglia 	struct blkcipher_desc desc;
51d22ef0bcSAnderson Briglia 	struct scatterlist sg;
52d22ef0bcSAnderson Briglia 	int err, iv_len;
53d22ef0bcSAnderson Briglia 	unsigned char iv[128];
54d22ef0bcSAnderson Briglia 
55d22ef0bcSAnderson Briglia 	if (tfm == NULL) {
56d22ef0bcSAnderson Briglia 		BT_ERR("tfm %p", tfm);
57d22ef0bcSAnderson Briglia 		return -EINVAL;
58d22ef0bcSAnderson Briglia 	}
59d22ef0bcSAnderson Briglia 
60d22ef0bcSAnderson Briglia 	desc.tfm = tfm;
61d22ef0bcSAnderson Briglia 	desc.flags = 0;
62d22ef0bcSAnderson Briglia 
63d22ef0bcSAnderson Briglia 	err = crypto_blkcipher_setkey(tfm, k, 16);
64d22ef0bcSAnderson Briglia 	if (err) {
65d22ef0bcSAnderson Briglia 		BT_ERR("cipher setkey failed: %d", err);
66d22ef0bcSAnderson Briglia 		return err;
67d22ef0bcSAnderson Briglia 	}
68d22ef0bcSAnderson Briglia 
69d22ef0bcSAnderson Briglia 	sg_init_one(&sg, r, 16);
70d22ef0bcSAnderson Briglia 
71d22ef0bcSAnderson Briglia 	iv_len = crypto_blkcipher_ivsize(tfm);
72d22ef0bcSAnderson Briglia 	if (iv_len) {
73d22ef0bcSAnderson Briglia 		memset(&iv, 0xff, iv_len);
74d22ef0bcSAnderson Briglia 		crypto_blkcipher_set_iv(tfm, iv, iv_len);
75d22ef0bcSAnderson Briglia 	}
76d22ef0bcSAnderson Briglia 
77d22ef0bcSAnderson Briglia 	err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
78d22ef0bcSAnderson Briglia 	if (err)
79d22ef0bcSAnderson Briglia 		BT_ERR("Encrypt data error %d", err);
80d22ef0bcSAnderson Briglia 
81d22ef0bcSAnderson Briglia 	return err;
82d22ef0bcSAnderson Briglia }
83d22ef0bcSAnderson Briglia 
84d22ef0bcSAnderson Briglia static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
85d22ef0bcSAnderson Briglia 		u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
86d22ef0bcSAnderson Briglia 		u8 _rat, bdaddr_t *ra, u8 res[16])
87d22ef0bcSAnderson Briglia {
88d22ef0bcSAnderson Briglia 	u8 p1[16], p2[16];
89d22ef0bcSAnderson Briglia 	int err;
90d22ef0bcSAnderson Briglia 
91d22ef0bcSAnderson Briglia 	memset(p1, 0, 16);
92d22ef0bcSAnderson Briglia 
93d22ef0bcSAnderson Briglia 	/* p1 = pres || preq || _rat || _iat */
94d22ef0bcSAnderson Briglia 	swap56(pres, p1);
95d22ef0bcSAnderson Briglia 	swap56(preq, p1 + 7);
96d22ef0bcSAnderson Briglia 	p1[14] = _rat;
97d22ef0bcSAnderson Briglia 	p1[15] = _iat;
98d22ef0bcSAnderson Briglia 
99d22ef0bcSAnderson Briglia 	memset(p2, 0, 16);
100d22ef0bcSAnderson Briglia 
101d22ef0bcSAnderson Briglia 	/* p2 = padding || ia || ra */
102d22ef0bcSAnderson Briglia 	baswap((bdaddr_t *) (p2 + 4), ia);
103d22ef0bcSAnderson Briglia 	baswap((bdaddr_t *) (p2 + 10), ra);
104d22ef0bcSAnderson Briglia 
105d22ef0bcSAnderson Briglia 	/* res = r XOR p1 */
106d22ef0bcSAnderson Briglia 	u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
107d22ef0bcSAnderson Briglia 
108d22ef0bcSAnderson Briglia 	/* res = e(k, res) */
109d22ef0bcSAnderson Briglia 	err = smp_e(tfm, k, res);
110d22ef0bcSAnderson Briglia 	if (err) {
111d22ef0bcSAnderson Briglia 		BT_ERR("Encrypt data error");
112d22ef0bcSAnderson Briglia 		return err;
113d22ef0bcSAnderson Briglia 	}
114d22ef0bcSAnderson Briglia 
115d22ef0bcSAnderson Briglia 	/* res = res XOR p2 */
116d22ef0bcSAnderson Briglia 	u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
117d22ef0bcSAnderson Briglia 
118d22ef0bcSAnderson Briglia 	/* res = e(k, res) */
119d22ef0bcSAnderson Briglia 	err = smp_e(tfm, k, res);
120d22ef0bcSAnderson Briglia 	if (err)
121d22ef0bcSAnderson Briglia 		BT_ERR("Encrypt data error");
122d22ef0bcSAnderson Briglia 
123d22ef0bcSAnderson Briglia 	return err;
124d22ef0bcSAnderson Briglia }
125d22ef0bcSAnderson Briglia 
126d22ef0bcSAnderson Briglia static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
127d22ef0bcSAnderson Briglia 			u8 r1[16], u8 r2[16], u8 _r[16])
128d22ef0bcSAnderson Briglia {
129d22ef0bcSAnderson Briglia 	int err;
130d22ef0bcSAnderson Briglia 
131d22ef0bcSAnderson Briglia 	/* Just least significant octets from r1 and r2 are considered */
132d22ef0bcSAnderson Briglia 	memcpy(_r, r1 + 8, 8);
133d22ef0bcSAnderson Briglia 	memcpy(_r + 8, r2 + 8, 8);
134d22ef0bcSAnderson Briglia 
135d22ef0bcSAnderson Briglia 	err = smp_e(tfm, k, _r);
136d22ef0bcSAnderson Briglia 	if (err)
137d22ef0bcSAnderson Briglia 		BT_ERR("Encrypt data error");
138d22ef0bcSAnderson Briglia 
139d22ef0bcSAnderson Briglia 	return err;
140d22ef0bcSAnderson Briglia }
141d22ef0bcSAnderson Briglia 
142d22ef0bcSAnderson Briglia static int smp_rand(u8 *buf)
143d22ef0bcSAnderson Briglia {
144d22ef0bcSAnderson Briglia 	get_random_bytes(buf, 16);
145d22ef0bcSAnderson Briglia 
146d22ef0bcSAnderson Briglia 	return 0;
147d22ef0bcSAnderson Briglia }
148eb492e01SAnderson Briglia 
149eb492e01SAnderson Briglia static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
150eb492e01SAnderson Briglia 						u16 dlen, void *data)
151eb492e01SAnderson Briglia {
152eb492e01SAnderson Briglia 	struct sk_buff *skb;
153eb492e01SAnderson Briglia 	struct l2cap_hdr *lh;
154eb492e01SAnderson Briglia 	int len;
155eb492e01SAnderson Briglia 
156eb492e01SAnderson Briglia 	len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
157eb492e01SAnderson Briglia 
158eb492e01SAnderson Briglia 	if (len > conn->mtu)
159eb492e01SAnderson Briglia 		return NULL;
160eb492e01SAnderson Briglia 
161eb492e01SAnderson Briglia 	skb = bt_skb_alloc(len, GFP_ATOMIC);
162eb492e01SAnderson Briglia 	if (!skb)
163eb492e01SAnderson Briglia 		return NULL;
164eb492e01SAnderson Briglia 
165eb492e01SAnderson Briglia 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
166eb492e01SAnderson Briglia 	lh->len = cpu_to_le16(sizeof(code) + dlen);
167eb492e01SAnderson Briglia 	lh->cid = cpu_to_le16(L2CAP_CID_SMP);
168eb492e01SAnderson Briglia 
169eb492e01SAnderson Briglia 	memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
170eb492e01SAnderson Briglia 
171eb492e01SAnderson Briglia 	memcpy(skb_put(skb, dlen), data, dlen);
172eb492e01SAnderson Briglia 
173eb492e01SAnderson Briglia 	return skb;
174eb492e01SAnderson Briglia }
175eb492e01SAnderson Briglia 
176eb492e01SAnderson Briglia static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
177eb492e01SAnderson Briglia {
178eb492e01SAnderson Briglia 	struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
179eb492e01SAnderson Briglia 
180eb492e01SAnderson Briglia 	BT_DBG("code 0x%2.2x", code);
181eb492e01SAnderson Briglia 
182eb492e01SAnderson Briglia 	if (!skb)
183eb492e01SAnderson Briglia 		return;
184eb492e01SAnderson Briglia 
18573d80debSLuiz Augusto von Dentz 	skb->priority = HCI_PRIO_MAX;
18673d80debSLuiz Augusto von Dentz 	hci_send_acl(conn->hchan, skb, 0);
187e2dcd113SVinicius Costa Gomes 
1886c9d42a1SGustavo F. Padovan 	cancel_delayed_work_sync(&conn->security_timer);
1896c9d42a1SGustavo F. Padovan 	schedule_delayed_work(&conn->security_timer,
190e2dcd113SVinicius Costa Gomes 					msecs_to_jiffies(SMP_TIMEOUT));
191eb492e01SAnderson Briglia }
192eb492e01SAnderson Briglia 
1932b64d153SBrian Gix static __u8 authreq_to_seclevel(__u8 authreq)
1942b64d153SBrian Gix {
1952b64d153SBrian Gix 	if (authreq & SMP_AUTH_MITM)
1962b64d153SBrian Gix 		return BT_SECURITY_HIGH;
1972b64d153SBrian Gix 	else
1982b64d153SBrian Gix 		return BT_SECURITY_MEDIUM;
1992b64d153SBrian Gix }
2002b64d153SBrian Gix 
2012b64d153SBrian Gix static __u8 seclevel_to_authreq(__u8 sec_level)
2022b64d153SBrian Gix {
2032b64d153SBrian Gix 	switch (sec_level) {
2042b64d153SBrian Gix 	case BT_SECURITY_HIGH:
2052b64d153SBrian Gix 		return SMP_AUTH_MITM | SMP_AUTH_BONDING;
2062b64d153SBrian Gix 	case BT_SECURITY_MEDIUM:
2072b64d153SBrian Gix 		return SMP_AUTH_BONDING;
2082b64d153SBrian Gix 	default:
2092b64d153SBrian Gix 		return SMP_AUTH_NONE;
2102b64d153SBrian Gix 	}
2112b64d153SBrian Gix }
2122b64d153SBrian Gix 
213b8e66eacSVinicius Costa Gomes static void build_pairing_cmd(struct l2cap_conn *conn,
21454790f73SVinicius Costa Gomes 				struct smp_cmd_pairing *req,
21554790f73SVinicius Costa Gomes 				struct smp_cmd_pairing *rsp,
21654790f73SVinicius Costa Gomes 				__u8 authreq)
217b8e66eacSVinicius Costa Gomes {
2182b64d153SBrian Gix 	u8 dist_keys = 0;
21954790f73SVinicius Costa Gomes 
220a8b2d5c2SJohan Hedberg 	if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
221ca10b5eeSVinicius Costa Gomes 		dist_keys = SMP_DIST_ENC_KEY;
22254790f73SVinicius Costa Gomes 		authreq |= SMP_AUTH_BONDING;
2232b64d153SBrian Gix 	} else {
2242b64d153SBrian Gix 		authreq &= ~SMP_AUTH_BONDING;
22554790f73SVinicius Costa Gomes 	}
22654790f73SVinicius Costa Gomes 
22754790f73SVinicius Costa Gomes 	if (rsp == NULL) {
22854790f73SVinicius Costa Gomes 		req->io_capability = conn->hcon->io_capability;
22954790f73SVinicius Costa Gomes 		req->oob_flag = SMP_OOB_NOT_PRESENT;
23054790f73SVinicius Costa Gomes 		req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
2312b64d153SBrian Gix 		req->init_key_dist = 0;
23254790f73SVinicius Costa Gomes 		req->resp_key_dist = dist_keys;
23354790f73SVinicius Costa Gomes 		req->auth_req = authreq;
23454790f73SVinicius Costa Gomes 		return;
23554790f73SVinicius Costa Gomes 	}
23654790f73SVinicius Costa Gomes 
23754790f73SVinicius Costa Gomes 	rsp->io_capability = conn->hcon->io_capability;
23854790f73SVinicius Costa Gomes 	rsp->oob_flag = SMP_OOB_NOT_PRESENT;
23954790f73SVinicius Costa Gomes 	rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
2402b64d153SBrian Gix 	rsp->init_key_dist = 0;
24154790f73SVinicius Costa Gomes 	rsp->resp_key_dist = req->resp_key_dist & dist_keys;
24254790f73SVinicius Costa Gomes 	rsp->auth_req = authreq;
243b8e66eacSVinicius Costa Gomes }
244b8e66eacSVinicius Costa Gomes 
2453158c50cSVinicius Costa Gomes static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
2463158c50cSVinicius Costa Gomes {
2471c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
2481c1def09SVinicius Costa Gomes 
2493158c50cSVinicius Costa Gomes 	if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
2503158c50cSVinicius Costa Gomes 			(max_key_size < SMP_MIN_ENC_KEY_SIZE))
2513158c50cSVinicius Costa Gomes 		return SMP_ENC_KEY_SIZE;
2523158c50cSVinicius Costa Gomes 
2531c1def09SVinicius Costa Gomes 	smp->smp_key_size = max_key_size;
2543158c50cSVinicius Costa Gomes 
2553158c50cSVinicius Costa Gomes 	return 0;
2563158c50cSVinicius Costa Gomes }
2573158c50cSVinicius Costa Gomes 
2584f957a76SBrian Gix static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
2594f957a76SBrian Gix {
2604f957a76SBrian Gix 	if (send)
2614f957a76SBrian Gix 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
2624f957a76SBrian Gix 								&reason);
2634f957a76SBrian Gix 
2644f957a76SBrian Gix 	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
2654f957a76SBrian Gix 	mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
2666c9d42a1SGustavo F. Padovan 	cancel_delayed_work_sync(&conn->security_timer);
2674f957a76SBrian Gix 	smp_chan_destroy(conn);
2684f957a76SBrian Gix }
2694f957a76SBrian Gix 
2702b64d153SBrian Gix #define JUST_WORKS	0x00
2712b64d153SBrian Gix #define JUST_CFM	0x01
2722b64d153SBrian Gix #define REQ_PASSKEY	0x02
2732b64d153SBrian Gix #define CFM_PASSKEY	0x03
2742b64d153SBrian Gix #define REQ_OOB		0x04
2752b64d153SBrian Gix #define OVERLAP		0xFF
2762b64d153SBrian Gix 
2772b64d153SBrian Gix static const u8 gen_method[5][5] = {
2782b64d153SBrian Gix 	{ JUST_WORKS,  JUST_CFM,    REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
2792b64d153SBrian Gix 	{ JUST_WORKS,  JUST_CFM,    REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
2802b64d153SBrian Gix 	{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
2812b64d153SBrian Gix 	{ JUST_WORKS,  JUST_CFM,    JUST_WORKS,  JUST_WORKS, JUST_CFM    },
2822b64d153SBrian Gix 	{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP     },
2832b64d153SBrian Gix };
2842b64d153SBrian Gix 
2852b64d153SBrian Gix static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
2862b64d153SBrian Gix 						u8 local_io, u8 remote_io)
2872b64d153SBrian Gix {
2882b64d153SBrian Gix 	struct hci_conn *hcon = conn->hcon;
2892b64d153SBrian Gix 	struct smp_chan *smp = conn->smp_chan;
2902b64d153SBrian Gix 	u8 method;
2912b64d153SBrian Gix 	u32 passkey = 0;
2922b64d153SBrian Gix 	int ret = 0;
2932b64d153SBrian Gix 
2942b64d153SBrian Gix 	/* Initialize key for JUST WORKS */
2952b64d153SBrian Gix 	memset(smp->tk, 0, sizeof(smp->tk));
2962b64d153SBrian Gix 	clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
2972b64d153SBrian Gix 
2982b64d153SBrian Gix 	BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
2992b64d153SBrian Gix 
3002b64d153SBrian Gix 	/* If neither side wants MITM, use JUST WORKS */
3012b64d153SBrian Gix 	/* If either side has unknown io_caps, use JUST WORKS */
3022b64d153SBrian Gix 	/* Otherwise, look up method from the table */
3032b64d153SBrian Gix 	if (!(auth & SMP_AUTH_MITM) ||
3042b64d153SBrian Gix 			local_io > SMP_IO_KEYBOARD_DISPLAY ||
3052b64d153SBrian Gix 			remote_io > SMP_IO_KEYBOARD_DISPLAY)
3062b64d153SBrian Gix 		method = JUST_WORKS;
3072b64d153SBrian Gix 	else
3082b64d153SBrian Gix 		method = gen_method[local_io][remote_io];
3092b64d153SBrian Gix 
3102b64d153SBrian Gix 	/* If not bonding, don't ask user to confirm a Zero TK */
3112b64d153SBrian Gix 	if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
3122b64d153SBrian Gix 		method = JUST_WORKS;
3132b64d153SBrian Gix 
3142b64d153SBrian Gix 	/* If Just Works, Continue with Zero TK */
3152b64d153SBrian Gix 	if (method == JUST_WORKS) {
3162b64d153SBrian Gix 		set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
3172b64d153SBrian Gix 		return 0;
3182b64d153SBrian Gix 	}
3192b64d153SBrian Gix 
3202b64d153SBrian Gix 	/* Not Just Works/Confirm results in MITM Authentication */
3212b64d153SBrian Gix 	if (method != JUST_CFM)
3222b64d153SBrian Gix 		set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags);
3232b64d153SBrian Gix 
3242b64d153SBrian Gix 	/* If both devices have Keyoard-Display I/O, the master
3252b64d153SBrian Gix 	 * Confirms and the slave Enters the passkey.
3262b64d153SBrian Gix 	 */
3272b64d153SBrian Gix 	if (method == OVERLAP) {
3282b64d153SBrian Gix 		if (hcon->link_mode & HCI_LM_MASTER)
3292b64d153SBrian Gix 			method = CFM_PASSKEY;
3302b64d153SBrian Gix 		else
3312b64d153SBrian Gix 			method = REQ_PASSKEY;
3322b64d153SBrian Gix 	}
3332b64d153SBrian Gix 
3342b64d153SBrian Gix 	/* Generate random passkey. Not valid until confirmed. */
3352b64d153SBrian Gix 	if (method == CFM_PASSKEY) {
3362b64d153SBrian Gix 		u8 key[16];
3372b64d153SBrian Gix 
3382b64d153SBrian Gix 		memset(key, 0, sizeof(key));
3392b64d153SBrian Gix 		get_random_bytes(&passkey, sizeof(passkey));
3402b64d153SBrian Gix 		passkey %= 1000000;
3412b64d153SBrian Gix 		put_unaligned_le32(passkey, key);
3422b64d153SBrian Gix 		swap128(key, smp->tk);
3432b64d153SBrian Gix 		BT_DBG("PassKey: %d", passkey);
3442b64d153SBrian Gix 	}
3452b64d153SBrian Gix 
3462b64d153SBrian Gix 	hci_dev_lock(hcon->hdev);
3472b64d153SBrian Gix 
3482b64d153SBrian Gix 	if (method == REQ_PASSKEY)
3492b64d153SBrian Gix 		ret = mgmt_user_passkey_request(hcon->hdev, conn->dst);
3502b64d153SBrian Gix 	else
3512b64d153SBrian Gix 		ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
3522b64d153SBrian Gix 						cpu_to_le32(passkey), 0);
3532b64d153SBrian Gix 
3542b64d153SBrian Gix 	hci_dev_unlock(hcon->hdev);
3552b64d153SBrian Gix 
3562b64d153SBrian Gix 	return ret;
3572b64d153SBrian Gix }
3582b64d153SBrian Gix 
3598aab4757SVinicius Costa Gomes static void confirm_work(struct work_struct *work)
3608aab4757SVinicius Costa Gomes {
3618aab4757SVinicius Costa Gomes 	struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
3628aab4757SVinicius Costa Gomes 	struct l2cap_conn *conn = smp->conn;
3638aab4757SVinicius Costa Gomes 	struct crypto_blkcipher *tfm;
3648aab4757SVinicius Costa Gomes 	struct smp_cmd_pairing_confirm cp;
3658aab4757SVinicius Costa Gomes 	int ret;
3668aab4757SVinicius Costa Gomes 	u8 res[16], reason;
3678aab4757SVinicius Costa Gomes 
3688aab4757SVinicius Costa Gomes 	BT_DBG("conn %p", conn);
3698aab4757SVinicius Costa Gomes 
3708aab4757SVinicius Costa Gomes 	tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
3718aab4757SVinicius Costa Gomes 	if (IS_ERR(tfm)) {
3728aab4757SVinicius Costa Gomes 		reason = SMP_UNSPECIFIED;
3738aab4757SVinicius Costa Gomes 		goto error;
3748aab4757SVinicius Costa Gomes 	}
3758aab4757SVinicius Costa Gomes 
3768aab4757SVinicius Costa Gomes 	smp->tfm = tfm;
3778aab4757SVinicius Costa Gomes 
3788aab4757SVinicius Costa Gomes 	if (conn->hcon->out)
3798aab4757SVinicius Costa Gomes 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
3808aab4757SVinicius Costa Gomes 				conn->src, conn->hcon->dst_type, conn->dst,
3818aab4757SVinicius Costa Gomes 				res);
3828aab4757SVinicius Costa Gomes 	else
3838aab4757SVinicius Costa Gomes 		ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
3848aab4757SVinicius Costa Gomes 				conn->hcon->dst_type, conn->dst, 0, conn->src,
3858aab4757SVinicius Costa Gomes 				res);
3868aab4757SVinicius Costa Gomes 	if (ret) {
3878aab4757SVinicius Costa Gomes 		reason = SMP_UNSPECIFIED;
3888aab4757SVinicius Costa Gomes 		goto error;
3898aab4757SVinicius Costa Gomes 	}
3908aab4757SVinicius Costa Gomes 
3912b64d153SBrian Gix 	clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
3922b64d153SBrian Gix 
3938aab4757SVinicius Costa Gomes 	swap128(res, cp.confirm_val);
3948aab4757SVinicius Costa Gomes 	smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
3958aab4757SVinicius Costa Gomes 
3968aab4757SVinicius Costa Gomes 	return;
3978aab4757SVinicius Costa Gomes 
3988aab4757SVinicius Costa Gomes error:
3994f957a76SBrian Gix 	smp_failure(conn, reason, 1);
4008aab4757SVinicius Costa Gomes }
4018aab4757SVinicius Costa Gomes 
4028aab4757SVinicius Costa Gomes static void random_work(struct work_struct *work)
4038aab4757SVinicius Costa Gomes {
4048aab4757SVinicius Costa Gomes 	struct smp_chan *smp = container_of(work, struct smp_chan, random);
4058aab4757SVinicius Costa Gomes 	struct l2cap_conn *conn = smp->conn;
4068aab4757SVinicius Costa Gomes 	struct hci_conn *hcon = conn->hcon;
4078aab4757SVinicius Costa Gomes 	struct crypto_blkcipher *tfm = smp->tfm;
4088aab4757SVinicius Costa Gomes 	u8 reason, confirm[16], res[16], key[16];
4098aab4757SVinicius Costa Gomes 	int ret;
4108aab4757SVinicius Costa Gomes 
4118aab4757SVinicius Costa Gomes 	if (IS_ERR_OR_NULL(tfm)) {
4128aab4757SVinicius Costa Gomes 		reason = SMP_UNSPECIFIED;
4138aab4757SVinicius Costa Gomes 		goto error;
4148aab4757SVinicius Costa Gomes 	}
4158aab4757SVinicius Costa Gomes 
4168aab4757SVinicius Costa Gomes 	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
4178aab4757SVinicius Costa Gomes 
4188aab4757SVinicius Costa Gomes 	if (hcon->out)
4198aab4757SVinicius Costa Gomes 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
4208aab4757SVinicius Costa Gomes 				conn->src, hcon->dst_type, conn->dst,
4218aab4757SVinicius Costa Gomes 				res);
4228aab4757SVinicius Costa Gomes 	else
4238aab4757SVinicius Costa Gomes 		ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
4248aab4757SVinicius Costa Gomes 				hcon->dst_type, conn->dst, 0, conn->src,
4258aab4757SVinicius Costa Gomes 				res);
4268aab4757SVinicius Costa Gomes 	if (ret) {
4278aab4757SVinicius Costa Gomes 		reason = SMP_UNSPECIFIED;
4288aab4757SVinicius Costa Gomes 		goto error;
4298aab4757SVinicius Costa Gomes 	}
4308aab4757SVinicius Costa Gomes 
4318aab4757SVinicius Costa Gomes 	swap128(res, confirm);
4328aab4757SVinicius Costa Gomes 
4338aab4757SVinicius Costa Gomes 	if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
4348aab4757SVinicius Costa Gomes 		BT_ERR("Pairing failed (confirmation values mismatch)");
4358aab4757SVinicius Costa Gomes 		reason = SMP_CONFIRM_FAILED;
4368aab4757SVinicius Costa Gomes 		goto error;
4378aab4757SVinicius Costa Gomes 	}
4388aab4757SVinicius Costa Gomes 
4398aab4757SVinicius Costa Gomes 	if (hcon->out) {
4408aab4757SVinicius Costa Gomes 		u8 stk[16], rand[8];
4418aab4757SVinicius Costa Gomes 		__le16 ediv;
4428aab4757SVinicius Costa Gomes 
4438aab4757SVinicius Costa Gomes 		memset(rand, 0, sizeof(rand));
4448aab4757SVinicius Costa Gomes 		ediv = 0;
4458aab4757SVinicius Costa Gomes 
4468aab4757SVinicius Costa Gomes 		smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
4478aab4757SVinicius Costa Gomes 		swap128(key, stk);
4488aab4757SVinicius Costa Gomes 
4498aab4757SVinicius Costa Gomes 		memset(stk + smp->smp_key_size, 0,
4508aab4757SVinicius Costa Gomes 				SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
4518aab4757SVinicius Costa Gomes 
4528aab4757SVinicius Costa Gomes 		if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
4538aab4757SVinicius Costa Gomes 			reason = SMP_UNSPECIFIED;
4548aab4757SVinicius Costa Gomes 			goto error;
4558aab4757SVinicius Costa Gomes 		}
4568aab4757SVinicius Costa Gomes 
4578aab4757SVinicius Costa Gomes 		hci_le_start_enc(hcon, ediv, rand, stk);
4588aab4757SVinicius Costa Gomes 		hcon->enc_key_size = smp->smp_key_size;
4598aab4757SVinicius Costa Gomes 	} else {
4608aab4757SVinicius Costa Gomes 		u8 stk[16], r[16], rand[8];
4618aab4757SVinicius Costa Gomes 		__le16 ediv;
4628aab4757SVinicius Costa Gomes 
4638aab4757SVinicius Costa Gomes 		memset(rand, 0, sizeof(rand));
4648aab4757SVinicius Costa Gomes 		ediv = 0;
4658aab4757SVinicius Costa Gomes 
4668aab4757SVinicius Costa Gomes 		swap128(smp->prnd, r);
4678aab4757SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
4688aab4757SVinicius Costa Gomes 
4698aab4757SVinicius Costa Gomes 		smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
4708aab4757SVinicius Costa Gomes 		swap128(key, stk);
4718aab4757SVinicius Costa Gomes 
4728aab4757SVinicius Costa Gomes 		memset(stk + smp->smp_key_size, 0,
4738aab4757SVinicius Costa Gomes 				SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
4748aab4757SVinicius Costa Gomes 
4758aab4757SVinicius Costa Gomes 		hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
4768aab4757SVinicius Costa Gomes 							ediv, rand, stk);
4778aab4757SVinicius Costa Gomes 	}
4788aab4757SVinicius Costa Gomes 
4798aab4757SVinicius Costa Gomes 	return;
4808aab4757SVinicius Costa Gomes 
4818aab4757SVinicius Costa Gomes error:
4824f957a76SBrian Gix 	smp_failure(conn, reason, 1);
4838aab4757SVinicius Costa Gomes }
4848aab4757SVinicius Costa Gomes 
4858aab4757SVinicius Costa Gomes static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
4868aab4757SVinicius Costa Gomes {
4878aab4757SVinicius Costa Gomes 	struct smp_chan *smp;
4888aab4757SVinicius Costa Gomes 
4898aab4757SVinicius Costa Gomes 	smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
4908aab4757SVinicius Costa Gomes 	if (!smp)
4918aab4757SVinicius Costa Gomes 		return NULL;
4928aab4757SVinicius Costa Gomes 
4938aab4757SVinicius Costa Gomes 	INIT_WORK(&smp->confirm, confirm_work);
4948aab4757SVinicius Costa Gomes 	INIT_WORK(&smp->random, random_work);
4958aab4757SVinicius Costa Gomes 
4968aab4757SVinicius Costa Gomes 	smp->conn = conn;
4978aab4757SVinicius Costa Gomes 	conn->smp_chan = smp;
4982b64d153SBrian Gix 	conn->hcon->smp_conn = conn;
4998aab4757SVinicius Costa Gomes 
5008aab4757SVinicius Costa Gomes 	hci_conn_hold(conn->hcon);
5018aab4757SVinicius Costa Gomes 
5028aab4757SVinicius Costa Gomes 	return smp;
5038aab4757SVinicius Costa Gomes }
5048aab4757SVinicius Costa Gomes 
5058aab4757SVinicius Costa Gomes void smp_chan_destroy(struct l2cap_conn *conn)
5068aab4757SVinicius Costa Gomes {
507c8eb9690SBrian Gix 	struct smp_chan *smp = conn->smp_chan;
508c8eb9690SBrian Gix 
509c8eb9690SBrian Gix 	clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
510c8eb9690SBrian Gix 
511c8eb9690SBrian Gix 	if (smp->tfm)
512c8eb9690SBrian Gix 		crypto_free_blkcipher(smp->tfm);
513c8eb9690SBrian Gix 
514c8eb9690SBrian Gix 	kfree(smp);
515c8eb9690SBrian Gix 	conn->smp_chan = NULL;
5162b64d153SBrian Gix 	conn->hcon->smp_conn = NULL;
5178aab4757SVinicius Costa Gomes 	hci_conn_put(conn->hcon);
5188aab4757SVinicius Costa Gomes }
5198aab4757SVinicius Costa Gomes 
5202b64d153SBrian Gix int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
5212b64d153SBrian Gix {
5222b64d153SBrian Gix 	struct l2cap_conn *conn = hcon->smp_conn;
5232b64d153SBrian Gix 	struct smp_chan *smp;
5242b64d153SBrian Gix 	u32 value;
5252b64d153SBrian Gix 	u8 key[16];
5262b64d153SBrian Gix 
5272b64d153SBrian Gix 	BT_DBG("");
5282b64d153SBrian Gix 
5292b64d153SBrian Gix 	if (!conn)
5302b64d153SBrian Gix 		return -ENOTCONN;
5312b64d153SBrian Gix 
5322b64d153SBrian Gix 	smp = conn->smp_chan;
5332b64d153SBrian Gix 
5342b64d153SBrian Gix 	switch (mgmt_op) {
5352b64d153SBrian Gix 	case MGMT_OP_USER_PASSKEY_REPLY:
5362b64d153SBrian Gix 		value = le32_to_cpu(passkey);
5372b64d153SBrian Gix 		memset(key, 0, sizeof(key));
5382b64d153SBrian Gix 		BT_DBG("PassKey: %d", value);
5392b64d153SBrian Gix 		put_unaligned_le32(value, key);
5402b64d153SBrian Gix 		swap128(key, smp->tk);
5412b64d153SBrian Gix 		/* Fall Through */
5422b64d153SBrian Gix 	case MGMT_OP_USER_CONFIRM_REPLY:
5432b64d153SBrian Gix 		set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
5442b64d153SBrian Gix 		break;
5452b64d153SBrian Gix 	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
5462b64d153SBrian Gix 	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
5472b64d153SBrian Gix 		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
5482b64d153SBrian Gix 		return 0;
5492b64d153SBrian Gix 	default:
5502b64d153SBrian Gix 		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
5512b64d153SBrian Gix 		return -EOPNOTSUPP;
5522b64d153SBrian Gix 	}
5532b64d153SBrian Gix 
5542b64d153SBrian Gix 	/* If it is our turn to send Pairing Confirm, do so now */
5552b64d153SBrian Gix 	if (test_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags))
5562b64d153SBrian Gix 		queue_work(hcon->hdev->workqueue, &smp->confirm);
5572b64d153SBrian Gix 
5582b64d153SBrian Gix 	return 0;
5592b64d153SBrian Gix }
5602b64d153SBrian Gix 
561da85e5e5SVinicius Costa Gomes static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
56288ba43b6SAnderson Briglia {
5633158c50cSVinicius Costa Gomes 	struct smp_cmd_pairing rsp, *req = (void *) skb->data;
5648aab4757SVinicius Costa Gomes 	struct smp_chan *smp;
5653158c50cSVinicius Costa Gomes 	u8 key_size;
5662b64d153SBrian Gix 	u8 auth = SMP_AUTH_NONE;
5678aab4757SVinicius Costa Gomes 	int ret;
56888ba43b6SAnderson Briglia 
56988ba43b6SAnderson Briglia 	BT_DBG("conn %p", conn);
57088ba43b6SAnderson Briglia 
5712b64d153SBrian Gix 	if (conn->hcon->link_mode & HCI_LM_MASTER)
5722b64d153SBrian Gix 		return SMP_CMD_NOTSUPP;
5732b64d153SBrian Gix 
574d26a2345SVinicius Costa Gomes 	if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
5758aab4757SVinicius Costa Gomes 		smp = smp_chan_create(conn);
5768aab4757SVinicius Costa Gomes 
5778aab4757SVinicius Costa Gomes 	smp = conn->smp_chan;
578d26a2345SVinicius Costa Gomes 
5791c1def09SVinicius Costa Gomes 	smp->preq[0] = SMP_CMD_PAIRING_REQ;
5801c1def09SVinicius Costa Gomes 	memcpy(&smp->preq[1], req, sizeof(*req));
5813158c50cSVinicius Costa Gomes 	skb_pull(skb, sizeof(*req));
58288ba43b6SAnderson Briglia 
5832b64d153SBrian Gix 	/* We didn't start the pairing, so match remote */
5842b64d153SBrian Gix 	if (req->auth_req & SMP_AUTH_BONDING)
5852b64d153SBrian Gix 		auth = req->auth_req;
586da85e5e5SVinicius Costa Gomes 
5872b64d153SBrian Gix 	build_pairing_cmd(conn, req, &rsp, auth);
5883158c50cSVinicius Costa Gomes 
5893158c50cSVinicius Costa Gomes 	key_size = min(req->max_key_size, rsp.max_key_size);
5903158c50cSVinicius Costa Gomes 	if (check_enc_key_size(conn, key_size))
5913158c50cSVinicius Costa Gomes 		return SMP_ENC_KEY_SIZE;
59288ba43b6SAnderson Briglia 
5938aab4757SVinicius Costa Gomes 	ret = smp_rand(smp->prnd);
5948aab4757SVinicius Costa Gomes 	if (ret)
5958aab4757SVinicius Costa Gomes 		return SMP_UNSPECIFIED;
5968aab4757SVinicius Costa Gomes 
5971c1def09SVinicius Costa Gomes 	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
5981c1def09SVinicius Costa Gomes 	memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
599f01ead31SAnderson Briglia 
6003158c50cSVinicius Costa Gomes 	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
601da85e5e5SVinicius Costa Gomes 
6022b64d153SBrian Gix 	/* Request setup of TK */
6032b64d153SBrian Gix 	ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
6042b64d153SBrian Gix 	if (ret)
6052b64d153SBrian Gix 		return SMP_UNSPECIFIED;
6062b64d153SBrian Gix 
607da85e5e5SVinicius Costa Gomes 	return 0;
60888ba43b6SAnderson Briglia }
60988ba43b6SAnderson Briglia 
610da85e5e5SVinicius Costa Gomes static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
61188ba43b6SAnderson Briglia {
6123158c50cSVinicius Costa Gomes 	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
6131c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
6148aab4757SVinicius Costa Gomes 	struct hci_dev *hdev = conn->hcon->hdev;
6152b64d153SBrian Gix 	u8 key_size, auth = SMP_AUTH_NONE;
6167d24ddccSAnderson Briglia 	int ret;
61788ba43b6SAnderson Briglia 
61888ba43b6SAnderson Briglia 	BT_DBG("conn %p", conn);
61988ba43b6SAnderson Briglia 
6202b64d153SBrian Gix 	if (!(conn->hcon->link_mode & HCI_LM_MASTER))
6212b64d153SBrian Gix 		return SMP_CMD_NOTSUPP;
6222b64d153SBrian Gix 
6233158c50cSVinicius Costa Gomes 	skb_pull(skb, sizeof(*rsp));
624da85e5e5SVinicius Costa Gomes 
6251c1def09SVinicius Costa Gomes 	req = (void *) &smp->preq[1];
6263158c50cSVinicius Costa Gomes 
6273158c50cSVinicius Costa Gomes 	key_size = min(req->max_key_size, rsp->max_key_size);
6283158c50cSVinicius Costa Gomes 	if (check_enc_key_size(conn, key_size))
6293158c50cSVinicius Costa Gomes 		return SMP_ENC_KEY_SIZE;
6303158c50cSVinicius Costa Gomes 
6311c1def09SVinicius Costa Gomes 	ret = smp_rand(smp->prnd);
6327d24ddccSAnderson Briglia 	if (ret)
633da85e5e5SVinicius Costa Gomes 		return SMP_UNSPECIFIED;
6347d24ddccSAnderson Briglia 
6358aab4757SVinicius Costa Gomes 	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
6368aab4757SVinicius Costa Gomes 	memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
6377d24ddccSAnderson Briglia 
6382b64d153SBrian Gix 	if ((req->auth_req & SMP_AUTH_BONDING) &&
6392b64d153SBrian Gix 			(rsp->auth_req & SMP_AUTH_BONDING))
6402b64d153SBrian Gix 		auth = SMP_AUTH_BONDING;
6412b64d153SBrian Gix 
6422b64d153SBrian Gix 	auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
6432b64d153SBrian Gix 
6442b64d153SBrian Gix 	ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability);
6452b64d153SBrian Gix 	if (ret)
6462b64d153SBrian Gix 		return SMP_UNSPECIFIED;
6472b64d153SBrian Gix 
6482b64d153SBrian Gix 	set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
6492b64d153SBrian Gix 
6502b64d153SBrian Gix 	/* Can't compose response until we have been confirmed */
6512b64d153SBrian Gix 	if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
6522b64d153SBrian Gix 		return 0;
6532b64d153SBrian Gix 
6548aab4757SVinicius Costa Gomes 	queue_work(hdev->workqueue, &smp->confirm);
655da85e5e5SVinicius Costa Gomes 
656da85e5e5SVinicius Costa Gomes 	return 0;
65788ba43b6SAnderson Briglia }
65888ba43b6SAnderson Briglia 
659da85e5e5SVinicius Costa Gomes static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
66088ba43b6SAnderson Briglia {
6611c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
6628aab4757SVinicius Costa Gomes 	struct hci_dev *hdev = conn->hcon->hdev;
6637d24ddccSAnderson Briglia 
66488ba43b6SAnderson Briglia 	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
66588ba43b6SAnderson Briglia 
6661c1def09SVinicius Costa Gomes 	memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
6671c1def09SVinicius Costa Gomes 	skb_pull(skb, sizeof(smp->pcnf));
6687d24ddccSAnderson Briglia 
66988ba43b6SAnderson Briglia 	if (conn->hcon->out) {
6707d24ddccSAnderson Briglia 		u8 random[16];
67188ba43b6SAnderson Briglia 
6721c1def09SVinicius Costa Gomes 		swap128(smp->prnd, random);
67388ba43b6SAnderson Briglia 		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
6747d24ddccSAnderson Briglia 								random);
6752b64d153SBrian Gix 	} else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
6768aab4757SVinicius Costa Gomes 		queue_work(hdev->workqueue, &smp->confirm);
6772b64d153SBrian Gix 	} else {
6782b64d153SBrian Gix 		set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
67988ba43b6SAnderson Briglia 	}
680da85e5e5SVinicius Costa Gomes 
681da85e5e5SVinicius Costa Gomes 	return 0;
68288ba43b6SAnderson Briglia }
68388ba43b6SAnderson Briglia 
684da85e5e5SVinicius Costa Gomes static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
68588ba43b6SAnderson Briglia {
6861c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
6878aab4757SVinicius Costa Gomes 	struct hci_dev *hdev = conn->hcon->hdev;
6887d24ddccSAnderson Briglia 
6898aab4757SVinicius Costa Gomes 	BT_DBG("conn %p", conn);
6907d24ddccSAnderson Briglia 
6918aab4757SVinicius Costa Gomes 	swap128(skb->data, smp->rrnd);
6928aab4757SVinicius Costa Gomes 	skb_pull(skb, sizeof(smp->rrnd));
69388ba43b6SAnderson Briglia 
6948aab4757SVinicius Costa Gomes 	queue_work(hdev->workqueue, &smp->random);
695da85e5e5SVinicius Costa Gomes 
696da85e5e5SVinicius Costa Gomes 	return 0;
69788ba43b6SAnderson Briglia }
69888ba43b6SAnderson Briglia 
699988c5997SVinicius Costa Gomes static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
700988c5997SVinicius Costa Gomes {
701988c5997SVinicius Costa Gomes 	struct link_key *key;
702988c5997SVinicius Costa Gomes 	struct key_master_id *master;
703988c5997SVinicius Costa Gomes 	struct hci_conn *hcon = conn->hcon;
704988c5997SVinicius Costa Gomes 
705988c5997SVinicius Costa Gomes 	key = hci_find_link_key_type(hcon->hdev, conn->dst,
706988c5997SVinicius Costa Gomes 						HCI_LK_SMP_LTK);
707988c5997SVinicius Costa Gomes 	if (!key)
708988c5997SVinicius Costa Gomes 		return 0;
709988c5997SVinicius Costa Gomes 
710988c5997SVinicius Costa Gomes 	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
711988c5997SVinicius Costa Gomes 					&hcon->pend))
712988c5997SVinicius Costa Gomes 		return 1;
713988c5997SVinicius Costa Gomes 
714988c5997SVinicius Costa Gomes 	master = (void *) key->data;
715988c5997SVinicius Costa Gomes 	hci_le_start_enc(hcon, master->ediv, master->rand,
716988c5997SVinicius Costa Gomes 						key->val);
717988c5997SVinicius Costa Gomes 	hcon->enc_key_size = key->pin_len;
718988c5997SVinicius Costa Gomes 
719988c5997SVinicius Costa Gomes 	return 1;
720988c5997SVinicius Costa Gomes 
721988c5997SVinicius Costa Gomes }
722da85e5e5SVinicius Costa Gomes static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
72388ba43b6SAnderson Briglia {
72488ba43b6SAnderson Briglia 	struct smp_cmd_security_req *rp = (void *) skb->data;
72588ba43b6SAnderson Briglia 	struct smp_cmd_pairing cp;
726f1cb9af5SVinicius Costa Gomes 	struct hci_conn *hcon = conn->hcon;
7278aab4757SVinicius Costa Gomes 	struct smp_chan *smp;
72888ba43b6SAnderson Briglia 
72988ba43b6SAnderson Briglia 	BT_DBG("conn %p", conn);
73088ba43b6SAnderson Briglia 
7312b64d153SBrian Gix 	hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
732feb45eb5SVinicius Costa Gomes 
733988c5997SVinicius Costa Gomes 	if (smp_ltk_encrypt(conn))
734988c5997SVinicius Costa Gomes 		return 0;
735988c5997SVinicius Costa Gomes 
736d26a2345SVinicius Costa Gomes 	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
737da85e5e5SVinicius Costa Gomes 		return 0;
738f1cb9af5SVinicius Costa Gomes 
7398aab4757SVinicius Costa Gomes 	smp = smp_chan_create(conn);
740d26a2345SVinicius Costa Gomes 
74188ba43b6SAnderson Briglia 	skb_pull(skb, sizeof(*rp));
74288ba43b6SAnderson Briglia 
743da85e5e5SVinicius Costa Gomes 	memset(&cp, 0, sizeof(cp));
74454790f73SVinicius Costa Gomes 	build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
74588ba43b6SAnderson Briglia 
7461c1def09SVinicius Costa Gomes 	smp->preq[0] = SMP_CMD_PAIRING_REQ;
7471c1def09SVinicius Costa Gomes 	memcpy(&smp->preq[1], &cp, sizeof(cp));
748f01ead31SAnderson Briglia 
74988ba43b6SAnderson Briglia 	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
750f1cb9af5SVinicius Costa Gomes 
751da85e5e5SVinicius Costa Gomes 	return 0;
75288ba43b6SAnderson Briglia }
75388ba43b6SAnderson Briglia 
754eb492e01SAnderson Briglia int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
755eb492e01SAnderson Briglia {
7563a0259bbSVinicius Costa Gomes 	struct hci_conn *hcon = conn->hcon;
7571c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
7582b64d153SBrian Gix 	__u8 authreq;
759eb492e01SAnderson Briglia 
7603a0259bbSVinicius Costa Gomes 	BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
7613a0259bbSVinicius Costa Gomes 
7622e65c9d2SAndre Guedes 	if (!lmp_host_le_capable(hcon->hdev))
7632e65c9d2SAndre Guedes 		return 1;
7642e65c9d2SAndre Guedes 
765f1cb9af5SVinicius Costa Gomes 	if (sec_level == BT_SECURITY_LOW)
766eb492e01SAnderson Briglia 		return 1;
767f1cb9af5SVinicius Costa Gomes 
768f1cb9af5SVinicius Costa Gomes 	if (hcon->sec_level >= sec_level)
769f1cb9af5SVinicius Costa Gomes 		return 1;
770f1cb9af5SVinicius Costa Gomes 
771988c5997SVinicius Costa Gomes 	if (hcon->link_mode & HCI_LM_MASTER)
772988c5997SVinicius Costa Gomes 		if (smp_ltk_encrypt(conn))
773d26a2345SVinicius Costa Gomes 			goto done;
774d26a2345SVinicius Costa Gomes 
775d26a2345SVinicius Costa Gomes 	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
776d26a2345SVinicius Costa Gomes 		return 0;
777d26a2345SVinicius Costa Gomes 
7788aab4757SVinicius Costa Gomes 	smp = smp_chan_create(conn);
7792b64d153SBrian Gix 	if (!smp)
7802b64d153SBrian Gix 		return 1;
7812b64d153SBrian Gix 
7822b64d153SBrian Gix 	authreq = seclevel_to_authreq(sec_level);
783d26a2345SVinicius Costa Gomes 
784d26a2345SVinicius Costa Gomes 	if (hcon->link_mode & HCI_LM_MASTER) {
785d26a2345SVinicius Costa Gomes 		struct smp_cmd_pairing cp;
786f01ead31SAnderson Briglia 
7872b64d153SBrian Gix 		build_pairing_cmd(conn, &cp, NULL, authreq);
7881c1def09SVinicius Costa Gomes 		smp->preq[0] = SMP_CMD_PAIRING_REQ;
7891c1def09SVinicius Costa Gomes 		memcpy(&smp->preq[1], &cp, sizeof(cp));
790f01ead31SAnderson Briglia 
791eb492e01SAnderson Briglia 		smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
792eb492e01SAnderson Briglia 	} else {
793eb492e01SAnderson Briglia 		struct smp_cmd_security_req cp;
7942b64d153SBrian Gix 		cp.auth_req = authreq;
795eb492e01SAnderson Briglia 		smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
796eb492e01SAnderson Briglia 	}
797eb492e01SAnderson Briglia 
79802bc7455SVinicius Costa Gomes done:
799f1cb9af5SVinicius Costa Gomes 	hcon->pending_sec_level = sec_level;
800f1cb9af5SVinicius Costa Gomes 
801eb492e01SAnderson Briglia 	return 0;
802eb492e01SAnderson Briglia }
803eb492e01SAnderson Briglia 
8047034b911SVinicius Costa Gomes static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
8057034b911SVinicius Costa Gomes {
80616b90839SVinicius Costa Gomes 	struct smp_cmd_encrypt_info *rp = (void *) skb->data;
8071c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
80816b90839SVinicius Costa Gomes 
80916b90839SVinicius Costa Gomes 	skb_pull(skb, sizeof(*rp));
81016b90839SVinicius Costa Gomes 
8111c1def09SVinicius Costa Gomes 	memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
81216b90839SVinicius Costa Gomes 
8137034b911SVinicius Costa Gomes 	return 0;
8147034b911SVinicius Costa Gomes }
8157034b911SVinicius Costa Gomes 
8167034b911SVinicius Costa Gomes static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
8177034b911SVinicius Costa Gomes {
81816b90839SVinicius Costa Gomes 	struct smp_cmd_master_ident *rp = (void *) skb->data;
8191c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
8207034b911SVinicius Costa Gomes 
82116b90839SVinicius Costa Gomes 	skb_pull(skb, sizeof(*rp));
82216b90839SVinicius Costa Gomes 
8233573b80cSHemant Gupta 	hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
8241c1def09SVinicius Costa Gomes 						rp->ediv, rp->rand, smp->tk);
8257034b911SVinicius Costa Gomes 
8267034b911SVinicius Costa Gomes 	smp_distribute_keys(conn, 1);
8277034b911SVinicius Costa Gomes 
8287034b911SVinicius Costa Gomes 	return 0;
8297034b911SVinicius Costa Gomes }
8307034b911SVinicius Costa Gomes 
831eb492e01SAnderson Briglia int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
832eb492e01SAnderson Briglia {
833eb492e01SAnderson Briglia 	__u8 code = skb->data[0];
834eb492e01SAnderson Briglia 	__u8 reason;
835eb492e01SAnderson Briglia 	int err = 0;
836eb492e01SAnderson Briglia 
8372e65c9d2SAndre Guedes 	if (!lmp_host_le_capable(conn->hcon->hdev)) {
8382e65c9d2SAndre Guedes 		err = -ENOTSUPP;
8392e65c9d2SAndre Guedes 		reason = SMP_PAIRING_NOTSUPP;
8402e65c9d2SAndre Guedes 		goto done;
8412e65c9d2SAndre Guedes 	}
8422e65c9d2SAndre Guedes 
843eb492e01SAnderson Briglia 	skb_pull(skb, sizeof(code));
844eb492e01SAnderson Briglia 
845eb492e01SAnderson Briglia 	switch (code) {
846eb492e01SAnderson Briglia 	case SMP_CMD_PAIRING_REQ:
847da85e5e5SVinicius Costa Gomes 		reason = smp_cmd_pairing_req(conn, skb);
848eb492e01SAnderson Briglia 		break;
849eb492e01SAnderson Briglia 
850eb492e01SAnderson Briglia 	case SMP_CMD_PAIRING_FAIL:
8514f957a76SBrian Gix 		smp_failure(conn, skb->data[0], 0);
852da85e5e5SVinicius Costa Gomes 		reason = 0;
853da85e5e5SVinicius Costa Gomes 		err = -EPERM;
854eb492e01SAnderson Briglia 		break;
855eb492e01SAnderson Briglia 
856eb492e01SAnderson Briglia 	case SMP_CMD_PAIRING_RSP:
857da85e5e5SVinicius Costa Gomes 		reason = smp_cmd_pairing_rsp(conn, skb);
85888ba43b6SAnderson Briglia 		break;
85988ba43b6SAnderson Briglia 
86088ba43b6SAnderson Briglia 	case SMP_CMD_SECURITY_REQ:
861da85e5e5SVinicius Costa Gomes 		reason = smp_cmd_security_req(conn, skb);
86288ba43b6SAnderson Briglia 		break;
86388ba43b6SAnderson Briglia 
864eb492e01SAnderson Briglia 	case SMP_CMD_PAIRING_CONFIRM:
865da85e5e5SVinicius Costa Gomes 		reason = smp_cmd_pairing_confirm(conn, skb);
86688ba43b6SAnderson Briglia 		break;
86788ba43b6SAnderson Briglia 
868eb492e01SAnderson Briglia 	case SMP_CMD_PAIRING_RANDOM:
869da85e5e5SVinicius Costa Gomes 		reason = smp_cmd_pairing_random(conn, skb);
87088ba43b6SAnderson Briglia 		break;
87188ba43b6SAnderson Briglia 
872eb492e01SAnderson Briglia 	case SMP_CMD_ENCRYPT_INFO:
8737034b911SVinicius Costa Gomes 		reason = smp_cmd_encrypt_info(conn, skb);
8747034b911SVinicius Costa Gomes 		break;
8757034b911SVinicius Costa Gomes 
876eb492e01SAnderson Briglia 	case SMP_CMD_MASTER_IDENT:
8777034b911SVinicius Costa Gomes 		reason = smp_cmd_master_ident(conn, skb);
8787034b911SVinicius Costa Gomes 		break;
8797034b911SVinicius Costa Gomes 
880eb492e01SAnderson Briglia 	case SMP_CMD_IDENT_INFO:
881eb492e01SAnderson Briglia 	case SMP_CMD_IDENT_ADDR_INFO:
882eb492e01SAnderson Briglia 	case SMP_CMD_SIGN_INFO:
8837034b911SVinicius Costa Gomes 		/* Just ignored */
8847034b911SVinicius Costa Gomes 		reason = 0;
8857034b911SVinicius Costa Gomes 		break;
8867034b911SVinicius Costa Gomes 
887eb492e01SAnderson Briglia 	default:
888eb492e01SAnderson Briglia 		BT_DBG("Unknown command code 0x%2.2x", code);
889eb492e01SAnderson Briglia 
890eb492e01SAnderson Briglia 		reason = SMP_CMD_NOTSUPP;
8913a0259bbSVinicius Costa Gomes 		err = -EOPNOTSUPP;
8923a0259bbSVinicius Costa Gomes 		goto done;
8933a0259bbSVinicius Costa Gomes 	}
8943a0259bbSVinicius Costa Gomes 
8953a0259bbSVinicius Costa Gomes done:
8963a0259bbSVinicius Costa Gomes 	if (reason)
8974f957a76SBrian Gix 		smp_failure(conn, reason, 1);
898eb492e01SAnderson Briglia 
899eb492e01SAnderson Briglia 	kfree_skb(skb);
900eb492e01SAnderson Briglia 	return err;
901eb492e01SAnderson Briglia }
9027034b911SVinicius Costa Gomes 
9037034b911SVinicius Costa Gomes int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
9047034b911SVinicius Costa Gomes {
9057034b911SVinicius Costa Gomes 	struct smp_cmd_pairing *req, *rsp;
9061c1def09SVinicius Costa Gomes 	struct smp_chan *smp = conn->smp_chan;
9077034b911SVinicius Costa Gomes 	__u8 *keydist;
9087034b911SVinicius Costa Gomes 
9097034b911SVinicius Costa Gomes 	BT_DBG("conn %p force %d", conn, force);
9107034b911SVinicius Costa Gomes 
911d26a2345SVinicius Costa Gomes 	if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
912d26a2345SVinicius Costa Gomes 		return 0;
913d26a2345SVinicius Costa Gomes 
9141c1def09SVinicius Costa Gomes 	rsp = (void *) &smp->prsp[1];
9157034b911SVinicius Costa Gomes 
9167034b911SVinicius Costa Gomes 	/* The responder sends its keys first */
9177034b911SVinicius Costa Gomes 	if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
9187034b911SVinicius Costa Gomes 		return 0;
9197034b911SVinicius Costa Gomes 
9201c1def09SVinicius Costa Gomes 	req = (void *) &smp->preq[1];
9217034b911SVinicius Costa Gomes 
9227034b911SVinicius Costa Gomes 	if (conn->hcon->out) {
9237034b911SVinicius Costa Gomes 		keydist = &rsp->init_key_dist;
9247034b911SVinicius Costa Gomes 		*keydist &= req->init_key_dist;
9257034b911SVinicius Costa Gomes 	} else {
9267034b911SVinicius Costa Gomes 		keydist = &rsp->resp_key_dist;
9277034b911SVinicius Costa Gomes 		*keydist &= req->resp_key_dist;
9287034b911SVinicius Costa Gomes 	}
9297034b911SVinicius Costa Gomes 
9307034b911SVinicius Costa Gomes 
9317034b911SVinicius Costa Gomes 	BT_DBG("keydist 0x%x", *keydist);
9327034b911SVinicius Costa Gomes 
9337034b911SVinicius Costa Gomes 	if (*keydist & SMP_DIST_ENC_KEY) {
9347034b911SVinicius Costa Gomes 		struct smp_cmd_encrypt_info enc;
9357034b911SVinicius Costa Gomes 		struct smp_cmd_master_ident ident;
9367034b911SVinicius Costa Gomes 		__le16 ediv;
9377034b911SVinicius Costa Gomes 
9387034b911SVinicius Costa Gomes 		get_random_bytes(enc.ltk, sizeof(enc.ltk));
9397034b911SVinicius Costa Gomes 		get_random_bytes(&ediv, sizeof(ediv));
9407034b911SVinicius Costa Gomes 		get_random_bytes(ident.rand, sizeof(ident.rand));
9417034b911SVinicius Costa Gomes 
9427034b911SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
9437034b911SVinicius Costa Gomes 
9441c1def09SVinicius Costa Gomes 		hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
945726b4ffcSVinicius Costa Gomes 						ediv, ident.rand, enc.ltk);
94616b90839SVinicius Costa Gomes 
9477034b911SVinicius Costa Gomes 		ident.ediv = cpu_to_le16(ediv);
9487034b911SVinicius Costa Gomes 
9497034b911SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
9507034b911SVinicius Costa Gomes 
9517034b911SVinicius Costa Gomes 		*keydist &= ~SMP_DIST_ENC_KEY;
9527034b911SVinicius Costa Gomes 	}
9537034b911SVinicius Costa Gomes 
9547034b911SVinicius Costa Gomes 	if (*keydist & SMP_DIST_ID_KEY) {
9557034b911SVinicius Costa Gomes 		struct smp_cmd_ident_addr_info addrinfo;
9567034b911SVinicius Costa Gomes 		struct smp_cmd_ident_info idinfo;
9577034b911SVinicius Costa Gomes 
9587034b911SVinicius Costa Gomes 		/* Send a dummy key */
9597034b911SVinicius Costa Gomes 		get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
9607034b911SVinicius Costa Gomes 
9617034b911SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
9627034b911SVinicius Costa Gomes 
9637034b911SVinicius Costa Gomes 		/* Just public address */
9647034b911SVinicius Costa Gomes 		memset(&addrinfo, 0, sizeof(addrinfo));
9657034b911SVinicius Costa Gomes 		bacpy(&addrinfo.bdaddr, conn->src);
9667034b911SVinicius Costa Gomes 
9677034b911SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
9687034b911SVinicius Costa Gomes 								&addrinfo);
9697034b911SVinicius Costa Gomes 
9707034b911SVinicius Costa Gomes 		*keydist &= ~SMP_DIST_ID_KEY;
9717034b911SVinicius Costa Gomes 	}
9727034b911SVinicius Costa Gomes 
9737034b911SVinicius Costa Gomes 	if (*keydist & SMP_DIST_SIGN) {
9747034b911SVinicius Costa Gomes 		struct smp_cmd_sign_info sign;
9757034b911SVinicius Costa Gomes 
9767034b911SVinicius Costa Gomes 		/* Send a dummy key */
9777034b911SVinicius Costa Gomes 		get_random_bytes(sign.csrk, sizeof(sign.csrk));
9787034b911SVinicius Costa Gomes 
9797034b911SVinicius Costa Gomes 		smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
9807034b911SVinicius Costa Gomes 
9817034b911SVinicius Costa Gomes 		*keydist &= ~SMP_DIST_SIGN;
9827034b911SVinicius Costa Gomes 	}
9837034b911SVinicius Costa Gomes 
984d26a2345SVinicius Costa Gomes 	if (conn->hcon->out || force) {
985d26a2345SVinicius Costa Gomes 		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
9866c9d42a1SGustavo F. Padovan 		cancel_delayed_work_sync(&conn->security_timer);
9878aab4757SVinicius Costa Gomes 		smp_chan_destroy(conn);
988d26a2345SVinicius Costa Gomes 	}
989d26a2345SVinicius Costa Gomes 
9907034b911SVinicius Costa Gomes 	return 0;
9917034b911SVinicius Costa Gomes }
992