aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_request.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-11-25 09:15:42 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-12-09 18:51:48 -0500
commitb1a8917c9bcbf42113dfacb6492228e094c96862 (patch)
tree30fbfaacbca3bc8775596c2107fa76cbe0cb8827 /net/bluetooth/hci_request.c
parent00cf5040b39638588cd10ae4ffcc76a1be6ecf2c (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.c189
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
437static 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
479static 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
512static 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
545static 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
593void __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
433void hci_req_add_le_scan_disable(struct hci_request *req) 622void 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;