diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2011-06-09 17:50:53 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 15:05:37 -0400 |
commit | da85e5e5afeb72bb6e6b5192a2d252861fafc3e7 (patch) | |
tree | 36fb5b1db3da5984f6ae45ce0b406f41b1a85ed2 /net/bluetooth/smp.c | |
parent | b8e66eacab21870d4f800822111c494f9ef291e3 (diff) |
Bluetooth: Add support for Pairing features exchange
This patch implements a simple version of the SMP Pairing Features
exchange procedure (Vol. 3 Part H, Section 2.3.5.1).
For now, everything that would cause a Pairing Method different of
Just Works to be chosen is rejected.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/smp.c')
-rw-r--r-- | net/bluetooth/smp.c | 106 |
1 files changed, 53 insertions, 53 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index d29700de5a44..dfd6891b9c86 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -181,6 +181,18 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) | |||
181 | hci_send_acl(conn->hcon, skb, 0); | 181 | hci_send_acl(conn->hcon, skb, 0); |
182 | } | 182 | } |
183 | 183 | ||
184 | static __u8 seclevel_to_authreq(__u8 level) | ||
185 | { | ||
186 | switch (level) { | ||
187 | case BT_SECURITY_HIGH: | ||
188 | /* Right now we don't support bonding */ | ||
189 | return SMP_AUTH_MITM; | ||
190 | |||
191 | default: | ||
192 | return SMP_AUTH_NONE; | ||
193 | } | ||
194 | } | ||
195 | |||
184 | static void build_pairing_cmd(struct l2cap_conn *conn, | 196 | static void build_pairing_cmd(struct l2cap_conn *conn, |
185 | struct smp_cmd_pairing *cmd, __u8 authreq) | 197 | struct smp_cmd_pairing *cmd, __u8 authreq) |
186 | { | 198 | { |
@@ -192,7 +204,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, | |||
192 | cmd->auth_req = authreq; | 204 | cmd->auth_req = authreq; |
193 | } | 205 | } |
194 | 206 | ||
195 | static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | 207 | static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) |
196 | { | 208 | { |
197 | struct smp_cmd_pairing *rp = (void *) skb->data; | 209 | struct smp_cmd_pairing *rp = (void *) skb->data; |
198 | 210 | ||
@@ -202,12 +214,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
202 | memcpy(&conn->preq[1], rp, sizeof(*rp)); | 214 | memcpy(&conn->preq[1], rp, sizeof(*rp)); |
203 | skb_pull(skb, sizeof(*rp)); | 215 | skb_pull(skb, sizeof(*rp)); |
204 | 216 | ||
205 | rp->io_capability = 0x00; | 217 | if (rp->oob_flag) |
206 | rp->oob_flag = 0x00; | 218 | return SMP_OOB_NOT_AVAIL; |
207 | rp->max_key_size = 16; | 219 | |
208 | rp->init_key_dist = 0x00; | 220 | /* We didn't start the pairing, so no requirements */ |
209 | rp->resp_key_dist = 0x00; | 221 | build_pairing_cmd(conn, rp, SMP_AUTH_NONE); |
210 | rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM); | ||
211 | 222 | ||
212 | /* Just works */ | 223 | /* Just works */ |
213 | memset(conn->tk, 0, sizeof(conn->tk)); | 224 | memset(conn->tk, 0, sizeof(conn->tk)); |
@@ -216,9 +227,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
216 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); | 227 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
217 | 228 | ||
218 | smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp); | 229 | smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp); |
230 | |||
231 | return 0; | ||
219 | } | 232 | } |
220 | 233 | ||
221 | static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | 234 | static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) |
222 | { | 235 | { |
223 | struct smp_cmd_pairing *rp = (void *) skb->data; | 236 | struct smp_cmd_pairing *rp = (void *) skb->data; |
224 | struct smp_cmd_pairing_confirm cp; | 237 | struct smp_cmd_pairing_confirm cp; |
@@ -228,29 +241,34 @@ static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |||
228 | 241 | ||
229 | BT_DBG("conn %p", conn); | 242 | BT_DBG("conn %p", conn); |
230 | 243 | ||
244 | skb_pull(skb, sizeof(*rp)); | ||
245 | |||
246 | if (rp->oob_flag) | ||
247 | return SMP_OOB_NOT_AVAIL; | ||
248 | |||
231 | /* Just works */ | 249 | /* Just works */ |
232 | memset(conn->tk, 0, sizeof(conn->tk)); | 250 | memset(conn->tk, 0, sizeof(conn->tk)); |
233 | 251 | ||
234 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; | 252 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; |
235 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); | 253 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
236 | skb_pull(skb, sizeof(*rp)); | ||
237 | 254 | ||
238 | ret = smp_rand(conn->prnd); | 255 | ret = smp_rand(conn->prnd); |
239 | if (ret) | 256 | if (ret) |
240 | return; | 257 | return SMP_UNSPECIFIED; |
241 | 258 | ||
242 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, | 259 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, |
243 | conn->src, conn->hcon->dst_type, conn->dst, res); | 260 | conn->src, conn->hcon->dst_type, conn->dst, res); |
244 | if (ret) | 261 | if (ret) |
245 | return; | 262 | return SMP_UNSPECIFIED; |
246 | 263 | ||
247 | swap128(res, cp.confirm_val); | 264 | swap128(res, cp.confirm_val); |
248 | 265 | ||
249 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); | 266 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); |
267 | |||
268 | return 0; | ||
250 | } | 269 | } |
251 | 270 | ||
252 | static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, | 271 | static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) |
253 | struct sk_buff *skb) | ||
254 | { | 272 | { |
255 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; | 273 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; |
256 | 274 | ||
@@ -272,21 +290,23 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, | |||
272 | 290 | ||
273 | ret = smp_rand(conn->prnd); | 291 | ret = smp_rand(conn->prnd); |
274 | if (ret) | 292 | if (ret) |
275 | return; | 293 | return SMP_UNSPECIFIED; |
276 | 294 | ||
277 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, | 295 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, |
278 | conn->hcon->dst_type, conn->dst, | 296 | conn->hcon->dst_type, conn->dst, |
279 | 0, conn->src, res); | 297 | 0, conn->src, res); |
280 | if (ret) | 298 | if (ret) |
281 | return; | 299 | return SMP_CONFIRM_FAILED; |
282 | 300 | ||
283 | swap128(res, cp.confirm_val); | 301 | swap128(res, cp.confirm_val); |
284 | 302 | ||
285 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); | 303 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); |
286 | } | 304 | } |
305 | |||
306 | return 0; | ||
287 | } | 307 | } |
288 | 308 | ||
289 | static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | 309 | static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) |
290 | { | 310 | { |
291 | struct hci_conn *hcon = conn->hcon; | 311 | struct hci_conn *hcon = conn->hcon; |
292 | struct crypto_blkcipher *tfm = hcon->hdev->tfm; | 312 | struct crypto_blkcipher *tfm = hcon->hdev->tfm; |
@@ -307,19 +327,15 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |||
307 | conn->hcon->dst_type, conn->dst, 0, conn->src, | 327 | conn->hcon->dst_type, conn->dst, 0, conn->src, |
308 | res); | 328 | res); |
309 | if (ret) | 329 | if (ret) |
310 | return; | 330 | return SMP_UNSPECIFIED; |
311 | 331 | ||
312 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); | 332 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
313 | 333 | ||
314 | swap128(res, confirm); | 334 | swap128(res, confirm); |
315 | 335 | ||
316 | if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { | 336 | if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { |
317 | struct smp_cmd_pairing_fail cp; | ||
318 | |||
319 | BT_ERR("Pairing failed (confirmation values mismatch)"); | 337 | BT_ERR("Pairing failed (confirmation values mismatch)"); |
320 | cp.reason = SMP_CONFIRM_FAILED; | 338 | return SMP_CONFIRM_FAILED; |
321 | smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(cp), &cp); | ||
322 | return; | ||
323 | } | 339 | } |
324 | 340 | ||
325 | if (conn->hcon->out) { | 341 | if (conn->hcon->out) { |
@@ -341,9 +357,11 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |||
341 | smp_s1(tfm, conn->tk, conn->prnd, random, key); | 357 | smp_s1(tfm, conn->tk, conn->prnd, random, key); |
342 | swap128(key, hcon->ltk); | 358 | swap128(key, hcon->ltk); |
343 | } | 359 | } |
360 | |||
361 | return 0; | ||
344 | } | 362 | } |
345 | 363 | ||
346 | static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | 364 | static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) |
347 | { | 365 | { |
348 | struct smp_cmd_security_req *rp = (void *) skb->data; | 366 | struct smp_cmd_security_req *rp = (void *) skb->data; |
349 | struct smp_cmd_pairing cp; | 367 | struct smp_cmd_pairing cp; |
@@ -352,17 +370,12 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
352 | BT_DBG("conn %p", conn); | 370 | BT_DBG("conn %p", conn); |
353 | 371 | ||
354 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) | 372 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) |
355 | return; | 373 | return 0; |
356 | 374 | ||
357 | skb_pull(skb, sizeof(*rp)); | 375 | skb_pull(skb, sizeof(*rp)); |
358 | memset(&cp, 0, sizeof(cp)); | ||
359 | 376 | ||
360 | cp.io_capability = 0x00; | 377 | memset(&cp, 0, sizeof(cp)); |
361 | cp.oob_flag = 0x00; | 378 | build_pairing_cmd(conn, &cp, rp->auth_req); |
362 | cp.max_key_size = 16; | ||
363 | cp.init_key_dist = 0x00; | ||
364 | cp.resp_key_dist = 0x00; | ||
365 | cp.auth_req = rp->auth_req & (SMP_AUTH_BONDING | SMP_AUTH_MITM); | ||
366 | 379 | ||
367 | conn->preq[0] = SMP_CMD_PAIRING_REQ; | 380 | conn->preq[0] = SMP_CMD_PAIRING_REQ; |
368 | memcpy(&conn->preq[1], &cp, sizeof(cp)); | 381 | memcpy(&conn->preq[1], &cp, sizeof(cp)); |
@@ -370,18 +383,8 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
370 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); | 383 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); |
371 | 384 | ||
372 | set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); | 385 | set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); |
373 | } | ||
374 | 386 | ||
375 | static __u8 seclevel_to_authreq(__u8 level) | 387 | return 0; |
376 | { | ||
377 | switch (level) { | ||
378 | case BT_SECURITY_HIGH: | ||
379 | /* For now we don't support bonding */ | ||
380 | return SMP_AUTH_MITM; | ||
381 | |||
382 | default: | ||
383 | return SMP_AUTH_NONE; | ||
384 | } | ||
385 | } | 388 | } |
386 | 389 | ||
387 | int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) | 390 | int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) |
@@ -407,13 +410,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) | |||
407 | 410 | ||
408 | if (hcon->link_mode & HCI_LM_MASTER) { | 411 | if (hcon->link_mode & HCI_LM_MASTER) { |
409 | struct smp_cmd_pairing cp; | 412 | struct smp_cmd_pairing cp; |
410 | cp.io_capability = 0x00; | ||
411 | cp.oob_flag = 0x00; | ||
412 | cp.max_key_size = 16; | ||
413 | cp.init_key_dist = 0x00; | ||
414 | cp.resp_key_dist = 0x00; | ||
415 | cp.auth_req = authreq; | ||
416 | 413 | ||
414 | build_pairing_cmd(conn, &cp, authreq); | ||
417 | conn->preq[0] = SMP_CMD_PAIRING_REQ; | 415 | conn->preq[0] = SMP_CMD_PAIRING_REQ; |
418 | memcpy(&conn->preq[1], &cp, sizeof(cp)); | 416 | memcpy(&conn->preq[1], &cp, sizeof(cp)); |
419 | 417 | ||
@@ -446,26 +444,28 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
446 | 444 | ||
447 | switch (code) { | 445 | switch (code) { |
448 | case SMP_CMD_PAIRING_REQ: | 446 | case SMP_CMD_PAIRING_REQ: |
449 | smp_cmd_pairing_req(conn, skb); | 447 | reason = smp_cmd_pairing_req(conn, skb); |
450 | break; | 448 | break; |
451 | 449 | ||
452 | case SMP_CMD_PAIRING_FAIL: | 450 | case SMP_CMD_PAIRING_FAIL: |
451 | reason = 0; | ||
452 | err = -EPERM; | ||
453 | break; | 453 | break; |
454 | 454 | ||
455 | case SMP_CMD_PAIRING_RSP: | 455 | case SMP_CMD_PAIRING_RSP: |
456 | smp_cmd_pairing_rsp(conn, skb); | 456 | reason = smp_cmd_pairing_rsp(conn, skb); |
457 | break; | 457 | break; |
458 | 458 | ||
459 | case SMP_CMD_SECURITY_REQ: | 459 | case SMP_CMD_SECURITY_REQ: |
460 | smp_cmd_security_req(conn, skb); | 460 | reason = smp_cmd_security_req(conn, skb); |
461 | break; | 461 | break; |
462 | 462 | ||
463 | case SMP_CMD_PAIRING_CONFIRM: | 463 | case SMP_CMD_PAIRING_CONFIRM: |
464 | smp_cmd_pairing_confirm(conn, skb); | 464 | reason = smp_cmd_pairing_confirm(conn, skb); |
465 | break; | 465 | break; |
466 | 466 | ||
467 | case SMP_CMD_PAIRING_RANDOM: | 467 | case SMP_CMD_PAIRING_RANDOM: |
468 | smp_cmd_pairing_random(conn, skb); | 468 | reason = smp_cmd_pairing_random(conn, skb); |
469 | break; | 469 | break; |
470 | 470 | ||
471 | case SMP_CMD_ENCRYPT_INFO: | 471 | case SMP_CMD_ENCRYPT_INFO: |