aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/mgmt.h6
-rw-r--r--net/bluetooth/mgmt.c53
2 files changed, 59 insertions, 0 deletions
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index d353d64bfffb..c2b4c83ab175 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -33,6 +33,12 @@ struct mgmt_rp_read_version {
33 __le16 revision; 33 __le16 revision;
34} __packed; 34} __packed;
35 35
36#define MGMT_OP_READ_INDEX_LIST 0x0003
37struct mgmt_rp_read_index_list {
38 __le16 num_controllers;
39 __le16 index[0];
40} __packed;
41
36#define MGMT_EV_CMD_COMPLETE 0x0001 42#define MGMT_EV_CMD_COMPLETE 0x0001
37struct mgmt_ev_cmd_complete { 43struct mgmt_ev_cmd_complete {
38 __le16 opcode; 44 __le16 opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3e24c0bf18e7..7a8e321875c9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -62,6 +62,56 @@ static int read_version(struct sock *sk)
62 return 0; 62 return 0;
63} 63}
64 64
65static int read_index_list(struct sock *sk)
66{
67 struct sk_buff *skb;
68 struct mgmt_hdr *hdr;
69 struct mgmt_ev_cmd_complete *ev;
70 struct mgmt_rp_read_index_list *rp;
71 struct list_head *p;
72 size_t body_len;
73 u16 count;
74 int i;
75
76 BT_DBG("sock %p", sk);
77
78 read_lock(&hci_dev_list_lock);
79
80 count = 0;
81 list_for_each(p, &hci_dev_list) {
82 count++;
83 }
84
85 body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
86 skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
87 if (!skb)
88 return -ENOMEM;
89
90 hdr = (void *) skb_put(skb, sizeof(*hdr));
91 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
92 hdr->len = cpu_to_le16(body_len);
93
94 ev = (void *) skb_put(skb, sizeof(*ev));
95 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
96
97 rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
98 put_unaligned_le16(count, &rp->num_controllers);
99
100 i = 0;
101 list_for_each(p, &hci_dev_list) {
102 struct hci_dev *d = list_entry(p, struct hci_dev, list);
103 put_unaligned_le16(d->id, &rp->index[i++]);
104 BT_DBG("Added hci%u", d->id);
105 }
106
107 read_unlock(&hci_dev_list_lock);
108
109 if (sock_queue_rcv_skb(sk, skb) < 0)
110 kfree_skb(skb);
111
112 return 0;
113}
114
65static int cmd_status(struct sock *sk, u16 cmd, u8 status) 115static int cmd_status(struct sock *sk, u16 cmd, u8 status)
66{ 116{
67 struct sk_buff *skb; 117 struct sk_buff *skb;
@@ -123,6 +173,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
123 case MGMT_OP_READ_VERSION: 173 case MGMT_OP_READ_VERSION:
124 err = read_version(sk); 174 err = read_version(sk);
125 break; 175 break;
176 case MGMT_OP_READ_INDEX_LIST:
177 err = read_index_list(sk);
178 break;
126 default: 179 default:
127 BT_DBG("Unknown op %u", opcode); 180 BT_DBG("Unknown op %u", opcode);
128 err = cmd_status(sk, opcode, 0x01); 181 err = cmd_status(sk, opcode, 0x01);