aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-01-21 06:56:35 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-07 22:40:07 -0500
commit2784eb41b1fbb3ff80f4921fe9dbb4c4acb6dc24 (patch)
treee13ea997be45f3d1abf5f3b4733a9da075a0410f /net/bluetooth/mgmt.c
parent17d5c04cb597418a177c3ca18dfde679636dd51c (diff)
Bluetooth: Add get_connections managment interface command
This patch adds a get_connections command to the management interface. With this command userspace can get the current list of connected devices. Typically this command would only be used once when enumerating existing adapters. After that the connected and disconnected events are used to track connections. 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.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9fb989f4216e..8f4f47e9d5c9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -941,6 +941,75 @@ failed:
941 return err; 941 return err;
942} 942}
943 943
944static int get_connections(struct sock *sk, unsigned char *data, u16 len)
945{
946 struct sk_buff *skb;
947 struct mgmt_hdr *hdr;
948 struct mgmt_cp_get_connections *cp;
949 struct mgmt_ev_cmd_complete *ev;
950 struct mgmt_rp_get_connections *rp;
951 struct hci_dev *hdev;
952 struct list_head *p;
953 size_t body_len;
954 u16 dev_id, count;
955 int i, err;
956
957 BT_DBG("");
958
959 cp = (void *) data;
960 dev_id = get_unaligned_le16(&cp->index);
961
962 hdev = hci_dev_get(dev_id);
963 if (!hdev)
964 return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
965
966 hci_dev_lock_bh(hdev);
967
968 count = 0;
969 list_for_each(p, &hdev->conn_hash.list) {
970 count++;
971 }
972
973 body_len = sizeof(*ev) + sizeof(*rp) + (count * sizeof(bdaddr_t));
974 skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
975 if (!skb) {
976 err = -ENOMEM;
977 goto unlock;
978 }
979
980 hdr = (void *) skb_put(skb, sizeof(*hdr));
981 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
982 hdr->len = cpu_to_le16(body_len);
983
984 ev = (void *) skb_put(skb, sizeof(*ev));
985 put_unaligned_le16(MGMT_OP_GET_CONNECTIONS, &ev->opcode);
986
987 rp = (void *) skb_put(skb, sizeof(*rp) + (count * sizeof(bdaddr_t)));
988 put_unaligned_le16(dev_id, &rp->index);
989 put_unaligned_le16(count, &rp->conn_count);
990
991 read_lock(&hci_dev_list_lock);
992
993 i = 0;
994 list_for_each(p, &hdev->conn_hash.list) {
995 struct hci_conn *c = list_entry(p, struct hci_conn, list);
996
997 bacpy(&rp->conn[i++], &c->dst);
998 }
999
1000 read_unlock(&hci_dev_list_lock);
1001
1002 if (sock_queue_rcv_skb(sk, skb) < 0)
1003 kfree_skb(skb);
1004
1005 err = 0;
1006
1007unlock:
1008 hci_dev_unlock_bh(hdev);
1009 hci_dev_put(hdev);
1010 return err;
1011}
1012
944int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 1013int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
945{ 1014{
946 unsigned char *buf; 1015 unsigned char *buf;
@@ -1014,6 +1083,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1014 case MGMT_OP_DISCONNECT: 1083 case MGMT_OP_DISCONNECT:
1015 err = disconnect(sk, buf + sizeof(*hdr), len); 1084 err = disconnect(sk, buf + sizeof(*hdr), len);
1016 break; 1085 break;
1086 case MGMT_OP_GET_CONNECTIONS:
1087 err = get_connections(sk, buf + sizeof(*hdr), len);
1088 break;
1017 default: 1089 default:
1018 BT_DBG("Unknown op %u", opcode); 1090 BT_DBG("Unknown op %u", opcode);
1019 err = cmd_status(sk, opcode, 0x01); 1091 err = cmd_status(sk, opcode, 0x01);