aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-01-04 05:08:51 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-07 22:40:05 -0500
commit2aeb9a1ae0e34fb46cb78b82f827a6a54ab65111 (patch)
tree3b308a5687cedc350cd562ec0ea7b1bf73e184ff /net/bluetooth
parentc542a06c29acbf4ea0024884a198065a10613147 (diff)
Bluetooth: Implement UUID handling through the management interface
This patch adds methods to the management interface for userspace to notify the kernel of which services have been registered for specific adapters. This information is needed for setting the appropriate Class of Device value as well as the Extended Inquiry Response value. This patch doesn't actually implement setting of these values but just provides the storage of the UUIDs so the needed functionality can be built on top of it. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_core.c19
-rw-r--r--net/bluetooth/mgmt.c120
2 files changed, 139 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 13eb5a8beb84..b99248d4a5b2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -955,6 +955,22 @@ void hci_del_off_timer(struct hci_dev *hdev)
955 del_timer(&hdev->off_timer); 955 del_timer(&hdev->off_timer);
956} 956}
957 957
958int hci_uuids_clear(struct hci_dev *hdev)
959{
960 struct list_head *p, *n;
961
962 list_for_each_safe(p, n, &hdev->uuids) {
963 struct bt_uuid *uuid;
964
965 uuid = list_entry(p, struct bt_uuid, list);
966
967 list_del(p);
968 kfree(uuid);
969 }
970
971 return 0;
972}
973
958/* Register HCI device */ 974/* Register HCI device */
959int hci_register_dev(struct hci_dev *hdev) 975int hci_register_dev(struct hci_dev *hdev)
960{ 976{
@@ -1012,6 +1028,8 @@ int hci_register_dev(struct hci_dev *hdev)
1012 1028
1013 INIT_LIST_HEAD(&hdev->blacklist); 1029 INIT_LIST_HEAD(&hdev->blacklist);
1014 1030
1031 INIT_LIST_HEAD(&hdev->uuids);
1032
1015 INIT_WORK(&hdev->power_on, hci_power_on); 1033 INIT_WORK(&hdev->power_on, hci_power_on);
1016 INIT_WORK(&hdev->power_off, hci_power_off); 1034 INIT_WORK(&hdev->power_off, hci_power_off);
1017 setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); 1035 setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1087,6 +1105,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
1087 1105
1088 hci_dev_lock_bh(hdev); 1106 hci_dev_lock_bh(hdev);
1089 hci_blacklist_clear(hdev); 1107 hci_blacklist_clear(hdev);
1108 hci_uuids_clear(hdev);
1090 hci_dev_unlock_bh(hdev); 1109 hci_dev_unlock_bh(hdev);
1091 1110
1092 __hci_dev_put(hdev); 1111 __hci_dev_put(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d10735076a25..0854c2f1073c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -571,6 +571,120 @@ failed:
571 return err; 571 return err;
572} 572}
573 573
574static int uuid_rsp(struct sock *sk, u16 opcode, u16 index)
575{
576 struct mgmt_hdr *hdr;
577 struct mgmt_ev_cmd_complete *ev;
578 struct sk_buff *skb;
579
580 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(index), GFP_ATOMIC);
581 if (!skb)
582 return -ENOMEM;
583
584 hdr = (void *) skb_put(skb, sizeof(*hdr));
585 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
586 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(index));
587
588 ev = (void *) skb_put(skb, sizeof(*ev));
589 put_unaligned_le16(opcode, &ev->opcode);
590
591 put_unaligned_le16(index, skb_put(skb, sizeof(index)));
592
593 if (sock_queue_rcv_skb(sk, skb) < 0)
594 kfree_skb(skb);
595
596 return 0;
597}
598
599static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
600{
601 struct mgmt_cp_add_uuid *cp;
602 struct hci_dev *hdev;
603 struct bt_uuid *uuid;
604 u16 dev_id;
605 int err;
606
607 cp = (void *) data;
608 dev_id = get_unaligned_le16(&cp->index);
609
610 BT_DBG("request for hci%u", dev_id);
611
612 hdev = hci_dev_get(dev_id);
613 if (!hdev)
614 return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
615
616 hci_dev_lock_bh(hdev);
617
618 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
619 if (!uuid) {
620 err = -ENOMEM;
621 goto failed;
622 }
623
624 memcpy(uuid->uuid, cp->uuid, 16);
625
626 list_add(&uuid->list, &hdev->uuids);
627
628 err = uuid_rsp(sk, MGMT_OP_ADD_UUID, dev_id);
629
630failed:
631 hci_dev_unlock_bh(hdev);
632 hci_dev_put(hdev);
633
634 return err;
635}
636
637static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
638{
639 struct list_head *p, *n;
640 struct mgmt_cp_add_uuid *cp;
641 struct hci_dev *hdev;
642 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
643 u16 dev_id;
644 int err, found;
645
646 cp = (void *) data;
647 dev_id = get_unaligned_le16(&cp->index);
648
649 BT_DBG("request for hci%u", dev_id);
650
651 hdev = hci_dev_get(dev_id);
652 if (!hdev)
653 return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
654
655 hci_dev_lock_bh(hdev);
656
657 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
658 err = hci_uuids_clear(hdev);
659 goto unlock;
660 }
661
662 found = 0;
663
664 list_for_each_safe(p, n, &hdev->uuids) {
665 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
666
667 if (memcmp(match->uuid, cp->uuid, 16) != 0)
668 continue;
669
670 list_del(&match->list);
671 found++;
672 }
673
674 if (found == 0) {
675 err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
676 goto unlock;
677 }
678
679 err = uuid_rsp(sk, MGMT_OP_REMOVE_UUID, dev_id);
680
681unlock:
682 hci_dev_unlock_bh(hdev);
683 hci_dev_put(hdev);
684
685 return err;
686}
687
574int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 688int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
575{ 689{
576 unsigned char *buf; 690 unsigned char *buf;
@@ -623,6 +737,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
623 case MGMT_OP_SET_PAIRABLE: 737 case MGMT_OP_SET_PAIRABLE:
624 err = set_pairable(sk, buf + sizeof(*hdr), len); 738 err = set_pairable(sk, buf + sizeof(*hdr), len);
625 break; 739 break;
740 case MGMT_OP_ADD_UUID:
741 err = add_uuid(sk, buf + sizeof(*hdr), len);
742 break;
743 case MGMT_OP_REMOVE_UUID:
744 err = remove_uuid(sk, buf + sizeof(*hdr), len);
745 break;
626 default: 746 default:
627 BT_DBG("Unknown op %u", opcode); 747 BT_DBG("Unknown op %u", opcode);
628 err = cmd_status(sk, opcode, 0x01); 748 err = cmd_status(sk, opcode, 0x01);