diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2015-11-25 09:15:42 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-12-09 18:51:48 -0500 |
commit | b1a8917c9bcbf42113dfacb6492228e094c96862 (patch) | |
tree | 30fbfaacbca3bc8775596c2107fa76cbe0cb8827 /net/bluetooth/hci_request.c | |
parent | 00cf5040b39638588cd10ae4ffcc76a1be6ecf2c (diff) |
Bluetooth: Move EIR update to hci_request.c
We'll soon need to update the EIR both from hci_request.c and mgmt.c
so move update_eir() as a more generic request helper to
hci_request.c.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_request.c')
-rw-r--r-- | net/bluetooth/hci_request.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 3150461c52a4..030a1bb66ef5 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c | |||
@@ -21,6 +21,8 @@ | |||
21 | SOFTWARE IS DISCLAIMED. | 21 | SOFTWARE IS DISCLAIMED. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <asm/unaligned.h> | ||
25 | |||
24 | #include <net/bluetooth/bluetooth.h> | 26 | #include <net/bluetooth/bluetooth.h> |
25 | #include <net/bluetooth/hci_core.h> | 27 | #include <net/bluetooth/hci_core.h> |
26 | #include <net/bluetooth/mgmt.h> | 28 | #include <net/bluetooth/mgmt.h> |
@@ -430,6 +432,193 @@ void __hci_req_update_name(struct hci_request *req) | |||
430 | hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); | 432 | hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); |
431 | } | 433 | } |
432 | 434 | ||
435 | #define PNP_INFO_SVCLASS_ID 0x1200 | ||
436 | |||
437 | static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) | ||
438 | { | ||
439 | u8 *ptr = data, *uuids_start = NULL; | ||
440 | struct bt_uuid *uuid; | ||
441 | |||
442 | if (len < 4) | ||
443 | return ptr; | ||
444 | |||
445 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
446 | u16 uuid16; | ||
447 | |||
448 | if (uuid->size != 16) | ||
449 | continue; | ||
450 | |||
451 | uuid16 = get_unaligned_le16(&uuid->uuid[12]); | ||
452 | if (uuid16 < 0x1100) | ||
453 | continue; | ||
454 | |||
455 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
456 | continue; | ||
457 | |||
458 | if (!uuids_start) { | ||
459 | uuids_start = ptr; | ||
460 | uuids_start[0] = 1; | ||
461 | uuids_start[1] = EIR_UUID16_ALL; | ||
462 | ptr += 2; | ||
463 | } | ||
464 | |||
465 | /* Stop if not enough space to put next UUID */ | ||
466 | if ((ptr - data) + sizeof(u16) > len) { | ||
467 | uuids_start[1] = EIR_UUID16_SOME; | ||
468 | break; | ||
469 | } | ||
470 | |||
471 | *ptr++ = (uuid16 & 0x00ff); | ||
472 | *ptr++ = (uuid16 & 0xff00) >> 8; | ||
473 | uuids_start[0] += sizeof(uuid16); | ||
474 | } | ||
475 | |||
476 | return ptr; | ||
477 | } | ||
478 | |||
479 | static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) | ||
480 | { | ||
481 | u8 *ptr = data, *uuids_start = NULL; | ||
482 | struct bt_uuid *uuid; | ||
483 | |||
484 | if (len < 6) | ||
485 | return ptr; | ||
486 | |||
487 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
488 | if (uuid->size != 32) | ||
489 | continue; | ||
490 | |||
491 | if (!uuids_start) { | ||
492 | uuids_start = ptr; | ||
493 | uuids_start[0] = 1; | ||
494 | uuids_start[1] = EIR_UUID32_ALL; | ||
495 | ptr += 2; | ||
496 | } | ||
497 | |||
498 | /* Stop if not enough space to put next UUID */ | ||
499 | if ((ptr - data) + sizeof(u32) > len) { | ||
500 | uuids_start[1] = EIR_UUID32_SOME; | ||
501 | break; | ||
502 | } | ||
503 | |||
504 | memcpy(ptr, &uuid->uuid[12], sizeof(u32)); | ||
505 | ptr += sizeof(u32); | ||
506 | uuids_start[0] += sizeof(u32); | ||
507 | } | ||
508 | |||
509 | return ptr; | ||
510 | } | ||
511 | |||
512 | static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) | ||
513 | { | ||
514 | u8 *ptr = data, *uuids_start = NULL; | ||
515 | struct bt_uuid *uuid; | ||
516 | |||
517 | if (len < 18) | ||
518 | return ptr; | ||
519 | |||
520 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
521 | if (uuid->size != 128) | ||
522 | continue; | ||
523 | |||
524 | if (!uuids_start) { | ||
525 | uuids_start = ptr; | ||
526 | uuids_start[0] = 1; | ||
527 | uuids_start[1] = EIR_UUID128_ALL; | ||
528 | ptr += 2; | ||
529 | } | ||
530 | |||
531 | /* Stop if not enough space to put next UUID */ | ||
532 | if ((ptr - data) + 16 > len) { | ||
533 | uuids_start[1] = EIR_UUID128_SOME; | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | memcpy(ptr, uuid->uuid, 16); | ||
538 | ptr += 16; | ||
539 | uuids_start[0] += 16; | ||
540 | } | ||
541 | |||
542 | return ptr; | ||
543 | } | ||
544 | |||
545 | static void create_eir(struct hci_dev *hdev, u8 *data) | ||
546 | { | ||
547 | u8 *ptr = data; | ||
548 | size_t name_len; | ||
549 | |||
550 | name_len = strlen(hdev->dev_name); | ||
551 | |||
552 | if (name_len > 0) { | ||
553 | /* EIR Data type */ | ||
554 | if (name_len > 48) { | ||
555 | name_len = 48; | ||
556 | ptr[1] = EIR_NAME_SHORT; | ||
557 | } else | ||
558 | ptr[1] = EIR_NAME_COMPLETE; | ||
559 | |||
560 | /* EIR Data length */ | ||
561 | ptr[0] = name_len + 1; | ||
562 | |||
563 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
564 | |||
565 | ptr += (name_len + 2); | ||
566 | } | ||
567 | |||
568 | if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) { | ||
569 | ptr[0] = 2; | ||
570 | ptr[1] = EIR_TX_POWER; | ||
571 | ptr[2] = (u8) hdev->inq_tx_power; | ||
572 | |||
573 | ptr += 3; | ||
574 | } | ||
575 | |||
576 | if (hdev->devid_source > 0) { | ||
577 | ptr[0] = 9; | ||
578 | ptr[1] = EIR_DEVICE_ID; | ||
579 | |||
580 | put_unaligned_le16(hdev->devid_source, ptr + 2); | ||
581 | put_unaligned_le16(hdev->devid_vendor, ptr + 4); | ||
582 | put_unaligned_le16(hdev->devid_product, ptr + 6); | ||
583 | put_unaligned_le16(hdev->devid_version, ptr + 8); | ||
584 | |||
585 | ptr += 10; | ||
586 | } | ||
587 | |||
588 | ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); | ||
589 | ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); | ||
590 | ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); | ||
591 | } | ||
592 | |||
593 | void __hci_req_update_eir(struct hci_request *req) | ||
594 | { | ||
595 | struct hci_dev *hdev = req->hdev; | ||
596 | struct hci_cp_write_eir cp; | ||
597 | |||
598 | if (!hdev_is_powered(hdev)) | ||
599 | return; | ||
600 | |||
601 | if (!lmp_ext_inq_capable(hdev)) | ||
602 | return; | ||
603 | |||
604 | if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) | ||
605 | return; | ||
606 | |||
607 | if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE)) | ||
608 | return; | ||
609 | |||
610 | memset(&cp, 0, sizeof(cp)); | ||
611 | |||
612 | create_eir(hdev, cp.data); | ||
613 | |||
614 | if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) | ||
615 | return; | ||
616 | |||
617 | memcpy(hdev->eir, cp.data, sizeof(cp.data)); | ||
618 | |||
619 | hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp); | ||
620 | } | ||
621 | |||
433 | void hci_req_add_le_scan_disable(struct hci_request *req) | 622 | void hci_req_add_le_scan_disable(struct hci_request *req) |
434 | { | 623 | { |
435 | struct hci_cp_le_set_scan_enable cp; | 624 | struct hci_cp_le_set_scan_enable cp; |