aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
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/mgmt.c
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/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d10735076a2..0854c2f1073 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);