Staging: hv: hv_mouse: clean up version structure usage
[pandora-kernel.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                 return -ENOMEM;
116
117         hdr = (void *) skb_put(skb, sizeof(*hdr));
118         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
119         hdr->len = cpu_to_le16(body_len);
120
121         ev = (void *) skb_put(skb, sizeof(*ev));
122         put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
123
124         rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
125         put_unaligned_le16(count, &rp->num_controllers);
126
127         i = 0;
128         list_for_each(p, &hci_dev_list) {
129                 struct hci_dev *d = list_entry(p, struct hci_dev, list);
130                 put_unaligned_le16(d->id, &rp->index[i++]);
131                 BT_DBG("Added hci%u", d->id);
132         }
133
134         read_unlock(&hci_dev_list_lock);
135
136         if (sock_queue_rcv_skb(sk, skb) < 0)
137                 kfree_skb(skb);
138
139         return 0;
140 }
141
142 static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
143 {
144         struct sk_buff *skb;
145         struct mgmt_hdr *hdr;
146         struct mgmt_ev_cmd_complete *ev;
147         struct mgmt_rp_read_info *rp;
148         struct mgmt_cp_read_info *cp;
149         struct hci_dev *hdev;
150         u16 dev_id;
151
152         BT_DBG("sock %p", sk);
153
154         if (len != 2)
155                 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
156
157         skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
158         if (!skb)
159                 return -ENOMEM;
160
161         hdr = (void *) skb_put(skb, sizeof(*hdr));
162         hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
163         hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
164
165         ev = (void *) skb_put(skb, sizeof(*ev));
166         put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
167
168         rp = (void *) skb_put(skb, sizeof(*rp));
169
170         cp = (void *) data;
171         dev_id = get_unaligned_le16(&cp->index);
172
173         BT_DBG("request for hci%u", dev_id);
174
175         hdev = hci_dev_get(dev_id);
176         if (!hdev) {
177                 kfree_skb(skb);
178                 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
179         }
180
181         hci_dev_lock_bh(hdev);
182
183         put_unaligned_le16(hdev->id, &rp->index);
184         rp->type = hdev->dev_type;
185
186         rp->powered = test_bit(HCI_UP, &hdev->flags);
187         rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
188         rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
189
190         if (test_bit(HCI_AUTH, &hdev->flags))
191                 rp->sec_mode = 3;
192         else if (hdev->ssp_mode > 0)
193                 rp->sec_mode = 4;
194         else
195                 rp->sec_mode = 2;
196
197         bacpy(&rp->bdaddr, &hdev->bdaddr);
198         memcpy(rp->features, hdev->features, 8);
199         memcpy(rp->dev_class, hdev->dev_class, 3);
200         put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
201         rp->hci_ver = hdev->hci_ver;
202         put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
203
204         hci_dev_unlock_bh(hdev);
205         hci_dev_put(hdev);
206
207         if (sock_queue_rcv_skb(sk, skb) < 0)
208                 kfree_skb(skb);
209
210         return 0;
211 }
212
213 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
214 {
215         unsigned char *buf;
216         struct mgmt_hdr *hdr;
217         u16 opcode, len;
218         int err;
219
220         BT_DBG("got %zu bytes", msglen);
221
222         if (msglen < sizeof(*hdr))
223                 return -EINVAL;
224
225         buf = kmalloc(msglen, GFP_ATOMIC);
226         if (!buf)
227                 return -ENOMEM;
228
229         if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
230                 err = -EFAULT;
231                 goto done;
232         }
233
234         hdr = (struct mgmt_hdr *) buf;
235         opcode = get_unaligned_le16(&hdr->opcode);
236         len = get_unaligned_le16(&hdr->len);
237
238         if (len != msglen - sizeof(*hdr)) {
239                 err = -EINVAL;
240                 goto done;
241         }
242
243         switch (opcode) {
244         case MGMT_OP_READ_VERSION:
245                 err = read_version(sk);
246                 break;
247         case MGMT_OP_READ_INDEX_LIST:
248                 err = read_index_list(sk);
249                 break;
250         case MGMT_OP_READ_INFO:
251                 err = read_controller_info(sk, buf + sizeof(*hdr), len);
252                 break;
253         default:
254                 BT_DBG("Unknown op %u", opcode);
255                 err = cmd_status(sk, opcode, 0x01);
256                 break;
257         }
258
259         if (err < 0)
260                 goto done;
261
262         err = msglen;
263
264 done:
265         kfree(buf);
266         return err;
267 }
268
269 static int mgmt_event(u16 event, void *data, u16 data_len)
270 {
271         struct sk_buff *skb;
272         struct mgmt_hdr *hdr;
273
274         skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
275         if (!skb)
276                 return -ENOMEM;
277
278         bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
279
280         hdr = (void *) skb_put(skb, sizeof(*hdr));
281         hdr->opcode = cpu_to_le16(event);
282         hdr->len = cpu_to_le16(data_len);
283
284         memcpy(skb_put(skb, data_len), data, data_len);
285
286         hci_send_to_sock(NULL, skb);
287         kfree_skb(skb);
288
289         return 0;
290 }
291
292 int mgmt_index_added(u16 index)
293 {
294         struct mgmt_ev_index_added ev;
295
296         put_unaligned_le16(index, &ev.index);
297
298         return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
299 }
300
301 int mgmt_index_removed(u16 index)
302 {
303         struct mgmt_ev_index_added ev;
304
305         put_unaligned_le16(index, &ev.index);
306
307         return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
308 }