diff options
-rw-r--r-- | include/net/bluetooth/mgmt.h | 10 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 72 |
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 | ||
134 | struct mgmt_cp_get_connections { | ||
135 | __le16 index; | ||
136 | } __packed; | ||
137 | struct 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 |
134 | struct mgmt_ev_cmd_complete { | 144 | struct 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 | ||
944 | static 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 | |||
1007 | unlock: | ||
1008 | hci_dev_unlock_bh(hdev); | ||
1009 | hci_dev_put(hdev); | ||
1010 | return err; | ||
1011 | } | ||
1012 | |||
944 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 1013 | int 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); |