Merge branch 'media_fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[cris-mirror.git] / net / bluetooth / mgmt.c
blobf827fd9083808f9126148cd8541fd29ad552b81b
1 /*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
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;
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.
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.
23 /* Bluetooth HCI Management interface */
25 #include <asm/uaccess.h>
26 #include <asm/unaligned.h>
28 #include <net/bluetooth/bluetooth.h>
29 #include <net/bluetooth/hci_core.h>
30 #include <net/bluetooth/mgmt.h>
32 #define MGMT_VERSION 0
33 #define MGMT_REVISION 1
35 static int cmd_status(struct sock *sk, u16 cmd, u8 status)
37 struct sk_buff *skb;
38 struct mgmt_hdr *hdr;
39 struct mgmt_ev_cmd_status *ev;
41 BT_DBG("sock %p", sk);
43 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
44 if (!skb)
45 return -ENOMEM;
47 hdr = (void *) skb_put(skb, sizeof(*hdr));
49 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
50 hdr->len = cpu_to_le16(sizeof(*ev));
52 ev = (void *) skb_put(skb, sizeof(*ev));
53 ev->status = status;
54 put_unaligned_le16(cmd, &ev->opcode);
56 if (sock_queue_rcv_skb(sk, skb) < 0)
57 kfree_skb(skb);
59 return 0;
62 static int read_version(struct sock *sk)
64 struct sk_buff *skb;
65 struct mgmt_hdr *hdr;
66 struct mgmt_ev_cmd_complete *ev;
67 struct mgmt_rp_read_version *rp;
69 BT_DBG("sock %p", sk);
71 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
72 if (!skb)
73 return -ENOMEM;
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));
79 ev = (void *) skb_put(skb, sizeof(*ev));
80 put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
82 rp = (void *) skb_put(skb, sizeof(*rp));
83 rp->version = MGMT_VERSION;
84 put_unaligned_le16(MGMT_REVISION, &rp->revision);
86 if (sock_queue_rcv_skb(sk, skb) < 0)
87 kfree_skb(skb);
89 return 0;
92 static int read_index_list(struct sock *sk)
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;
103 BT_DBG("sock %p", sk);
105 read_lock(&hci_dev_list_lock);
107 count = 0;
108 list_for_each(p, &hci_dev_list) {
109 count++;
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;
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);
121 ev = (void *) skb_put(skb, sizeof(*ev));
122 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
124 rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
125 put_unaligned_le16(count, &rp->num_controllers);
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);
134 read_unlock(&hci_dev_list_lock);
136 if (sock_queue_rcv_skb(sk, skb) < 0)
137 kfree_skb(skb);
139 return 0;
142 static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
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;
152 BT_DBG("sock %p", sk);
154 if (len != 2)
155 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
157 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
158 if (!skb)
159 return -ENOMEM;
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));
165 ev = (void *) skb_put(skb, sizeof(*ev));
166 put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
168 rp = (void *) skb_put(skb, sizeof(*rp));
170 cp = (void *) data;
171 dev_id = get_unaligned_le16(&cp->index);
173 BT_DBG("request for hci%u", dev_id);
175 hdev = hci_dev_get(dev_id);
176 if (!hdev) {
177 kfree_skb(skb);
178 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
181 hci_dev_lock_bh(hdev);
183 put_unaligned_le16(hdev->id, &rp->index);
184 rp->type = hdev->dev_type;
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);
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;
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);
204 hci_dev_unlock_bh(hdev);
205 hci_dev_put(hdev);
207 if (sock_queue_rcv_skb(sk, skb) < 0)
208 kfree_skb(skb);
210 return 0;
213 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
215 unsigned char *buf;
216 struct mgmt_hdr *hdr;
217 u16 opcode, len;
218 int err;
220 BT_DBG("got %zu bytes", msglen);
222 if (msglen < sizeof(*hdr))
223 return -EINVAL;
225 buf = kmalloc(msglen, GFP_ATOMIC);
226 if (!buf)
227 return -ENOMEM;
229 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
230 err = -EFAULT;
231 goto done;
234 hdr = (struct mgmt_hdr *) buf;
235 opcode = get_unaligned_le16(&hdr->opcode);
236 len = get_unaligned_le16(&hdr->len);
238 if (len != msglen - sizeof(*hdr)) {
239 err = -EINVAL;
240 goto done;
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;
259 if (err < 0)
260 goto done;
262 err = msglen;
264 done:
265 kfree(buf);
266 return err;
269 static int mgmt_event(u16 event, void *data, u16 data_len)
271 struct sk_buff *skb;
272 struct mgmt_hdr *hdr;
274 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
275 if (!skb)
276 return -ENOMEM;
278 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
280 hdr = (void *) skb_put(skb, sizeof(*hdr));
281 hdr->opcode = cpu_to_le16(event);
282 hdr->len = cpu_to_le16(data_len);
284 memcpy(skb_put(skb, data_len), data, data_len);
286 hci_send_to_sock(NULL, skb);
287 kfree_skb(skb);
289 return 0;
292 int mgmt_index_added(u16 index)
294 struct mgmt_ev_index_added ev;
296 put_unaligned_le16(index, &ev.index);
298 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
301 int mgmt_index_removed(u16 index)
303 struct mgmt_ev_index_added ev;
305 put_unaligned_le16(index, &ev.index);
307 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));