]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/bluetooth/mgmt.c
Bluetooth: Fix failure to release lock in read_index_list()
[karo-tx-linux.git] / net / bluetooth / mgmt.c
1 /*
2    BlueZ - Bluetooth protocol stack for Linux
3    Copyright (C) 2010  Nokia Corporation
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation;
8
9    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20    SOFTWARE IS DISCLAIMED.
21 */
22
23 /* Bluetooth HCI Management interface */
24
25 #include <asm/uaccess.h>
26 #include <asm/unaligned.h>
27
28 #include <net/bluetooth/bluetooth.h>
29 #include <net/bluetooth/hci_core.h>
30 #include <net/bluetooth/mgmt.h>
31
32 #define MGMT_VERSION    0
33 #define MGMT_REVISION   1
34
35 static int cmd_status(struct sock *sk, u16 cmd, u8 status)
36 {
37         struct sk_buff *skb;
38         struct mgmt_hdr *hdr;
39         struct mgmt_ev_cmd_status *ev;
40
41         BT_DBG("sock %p", sk);
42
43         skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
44         if (!skb)
45                 return -ENOMEM;
46
47         hdr = (void *) skb_put(skb, sizeof(*hdr));
48
49         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
50         hdr->len = cpu_to_le16(sizeof(*ev));
51
52         ev = (void *) skb_put(skb, sizeof(*ev));
53         ev->status = status;
54         put_unaligned_le16(cmd, &ev->opcode);
55
56         if (sock_queue_rcv_skb(sk, skb) < 0)
57                 kfree_skb(skb);
58
59         return 0;
60 }
61
62 static int read_version(struct sock *sk)
63 {
64         struct sk_buff *skb;
65         struct mgmt_hdr *hdr;
66         struct mgmt_ev_cmd_complete *ev;
67         struct mgmt_rp_read_version *rp;
68
69         BT_DBG("sock %p", sk);
70
71         skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
72         if (!skb)
73                 return -ENOMEM;
74
75         hdr = (void *) skb_put(skb, sizeof(*hdr));
76         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
77         hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
78
79         ev = (void *) skb_put(skb, sizeof(*ev));
80         put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
81
82         rp = (void *) skb_put(skb, sizeof(*rp));
83         rp->version = MGMT_VERSION;
84         put_unaligned_le16(MGMT_REVISION, &rp->revision);
85
86         if (sock_queue_rcv_skb(sk, skb) < 0)
87                 kfree_skb(skb);
88
89         return 0;
90 }
91
92 static int read_index_list(struct sock *sk)
93 {
94         struct sk_buff *skb;
95         struct mgmt_hdr *hdr;
96         struct mgmt_ev_cmd_complete *ev;
97         struct mgmt_rp_read_index_list *rp;
98         struct list_head *p;
99         size_t body_len;
100         u16 count;
101         int i;
102
103         BT_DBG("sock %p", sk);
104
105         read_lock(&hci_dev_list_lock);
106
107         count = 0;
108         list_for_each(p, &hci_dev_list) {
109                 count++;
110         }
111
112         body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
113         skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
114         if (!skb) {
115                 read_unlock(&hci_dev_list_lock);
116                 return -ENOMEM;
117         }
118
119         hdr = (void *) skb_put(skb, sizeof(*hdr));
120         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
121         hdr->len = cpu_to_le16(body_len);
122
123         ev = (void *) skb_put(skb, sizeof(*ev));
124         put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
125
126         rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
127         put_unaligned_le16(count, &rp->num_controllers);
128
129         i = 0;
130         list_for_each(p, &hci_dev_list) {
131                 struct hci_dev *d = list_entry(p, struct hci_dev, list);
132                 put_unaligned_le16(d->id, &rp->index[i++]);
133                 BT_DBG("Added hci%u", d->id);
134         }
135
136         read_unlock(&hci_dev_list_lock);
137
138         if (sock_queue_rcv_skb(sk, skb) < 0)
139                 kfree_skb(skb);
140
141         return 0;
142 }
143
144 static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
145 {
146         struct sk_buff *skb;
147         struct mgmt_hdr *hdr;
148         struct mgmt_ev_cmd_complete *ev;
149         struct mgmt_rp_read_info *rp;
150         struct mgmt_cp_read_info *cp;
151         struct hci_dev *hdev;
152         u16 dev_id;
153
154         BT_DBG("sock %p", sk);
155
156         if (len != 2)
157                 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
158
159         skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
160         if (!skb)
161                 return -ENOMEM;
162
163         hdr = (void *) skb_put(skb, sizeof(*hdr));
164         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
165         hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
166
167         ev = (void *) skb_put(skb, sizeof(*ev));
168         put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
169
170         rp = (void *) skb_put(skb, sizeof(*rp));
171
172         cp = (void *) data;
173         dev_id = get_unaligned_le16(&cp->index);
174
175         BT_DBG("request for hci%u", dev_id);
176
177         hdev = hci_dev_get(dev_id);
178         if (!hdev) {
179                 kfree_skb(skb);
180                 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
181         }
182
183         hci_dev_lock_bh(hdev);
184
185         put_unaligned_le16(hdev->id, &rp->index);
186         rp->type = hdev->dev_type;
187
188         rp->powered = test_bit(HCI_UP, &hdev->flags);
189         rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
190         rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
191
192         if (test_bit(HCI_AUTH, &hdev->flags))
193                 rp->sec_mode = 3;
194         else if (hdev->ssp_mode > 0)
195                 rp->sec_mode = 4;
196         else
197                 rp->sec_mode = 2;
198
199         bacpy(&rp->bdaddr, &hdev->bdaddr);
200         memcpy(rp->features, hdev->features, 8);
201         memcpy(rp->dev_class, hdev->dev_class, 3);
202         put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
203         rp->hci_ver = hdev->hci_ver;
204         put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
205
206         hci_dev_unlock_bh(hdev);
207         hci_dev_put(hdev);
208
209         if (sock_queue_rcv_skb(sk, skb) < 0)
210                 kfree_skb(skb);
211
212         return 0;
213 }
214
215 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
216 {
217         unsigned char *buf;
218         struct mgmt_hdr *hdr;
219         u16 opcode, len;
220         int err;
221
222         BT_DBG("got %zu bytes", msglen);
223
224         if (msglen < sizeof(*hdr))
225                 return -EINVAL;
226
227         buf = kmalloc(msglen, GFP_ATOMIC);
228         if (!buf)
229                 return -ENOMEM;
230
231         if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
232                 err = -EFAULT;
233                 goto done;
234         }
235
236         hdr = (struct mgmt_hdr *) buf;
237         opcode = get_unaligned_le16(&hdr->opcode);
238         len = get_unaligned_le16(&hdr->len);
239
240         if (len != msglen - sizeof(*hdr)) {
241                 err = -EINVAL;
242                 goto done;
243         }
244
245         switch (opcode) {
246         case MGMT_OP_READ_VERSION:
247                 err = read_version(sk);
248                 break;
249         case MGMT_OP_READ_INDEX_LIST:
250                 err = read_index_list(sk);
251                 break;
252         case MGMT_OP_READ_INFO:
253                 err = read_controller_info(sk, buf + sizeof(*hdr), len);
254                 break;
255         default:
256                 BT_DBG("Unknown op %u", opcode);
257                 err = cmd_status(sk, opcode, 0x01);
258                 break;
259         }
260
261         if (err < 0)
262                 goto done;
263
264         err = msglen;
265
266 done:
267         kfree(buf);
268         return err;
269 }
270
271 static int mgmt_event(u16 event, void *data, u16 data_len)
272 {
273         struct sk_buff *skb;
274         struct mgmt_hdr *hdr;
275
276         skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
277         if (!skb)
278                 return -ENOMEM;
279
280         bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
281
282         hdr = (void *) skb_put(skb, sizeof(*hdr));
283         hdr->opcode = cpu_to_le16(event);
284         hdr->len = cpu_to_le16(data_len);
285
286         memcpy(skb_put(skb, data_len), data, data_len);
287
288         hci_send_to_sock(NULL, skb);
289         kfree_skb(skb);
290
291         return 0;
292 }
293
294 int mgmt_index_added(u16 index)
295 {
296         struct mgmt_ev_index_added ev;
297
298         put_unaligned_le16(index, &ev.index);
299
300         return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
301 }
302
303 int mgmt_index_removed(u16 index)
304 {
305         struct mgmt_ev_index_added ev;
306
307         put_unaligned_le16(index, &ev.index);
308
309         return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
310 }