aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/mgmt.h10
-rw-r--r--net/bluetooth/mgmt.c72
2 files changed, 82 insertions, 0 deletions
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 1d822f2c0f1a..3d8d589fa559 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -130,6 +130,16 @@ struct mgmt_rp_disconnect {
130 bdaddr_t bdaddr; 130 bdaddr_t bdaddr;
131} __packed; 131} __packed;
132 132
133#define MGMT_OP_GET_CONNECTIONS 0x0010
134struct mgmt_cp_get_connections {
135 __le16 index;
136} __packed;
137struct mgmt_rp_get_connections {
138 __le16 index;
139 __le16 conn_count;
140 bdaddr_t conn[0];
141} __packed;
142
133#define MGMT_EV_CMD_COMPLETE 0x0001 143#define MGMT_EV_CMD_COMPLETE 0x0001
134struct mgmt_ev_cmd_complete { 144struct mgmt_ev_cmd_complete {
135 __le16 opcode; 145 __le16 opcode;
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);