blob: 52e5f88b753a9ea144d056893d830877eb4c8fd2 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
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
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#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
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
41};
42
43LIST_HEAD(cmd_list);
44
Johan Hedbergf7b64e692010-12-13 21:07:06 +020045static int cmd_status(struct sock *sk, u16 cmd, u8 status)
46{
47 struct sk_buff *skb;
48 struct mgmt_hdr *hdr;
49 struct mgmt_ev_cmd_status *ev;
50
51 BT_DBG("sock %p", sk);
52
53 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
54 if (!skb)
55 return -ENOMEM;
56
57 hdr = (void *) skb_put(skb, sizeof(*hdr));
58
59 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
60 hdr->len = cpu_to_le16(sizeof(*ev));
61
62 ev = (void *) skb_put(skb, sizeof(*ev));
63 ev->status = status;
64 put_unaligned_le16(cmd, &ev->opcode);
65
66 if (sock_queue_rcv_skb(sk, skb) < 0)
67 kfree_skb(skb);
68
69 return 0;
70}
71
Johan Hedberga38528f2011-01-22 06:46:43 +020072static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020073{
74 struct sk_buff *skb;
75 struct mgmt_hdr *hdr;
76 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020077
78 BT_DBG("sock %p", sk);
79
Johan Hedberga38528f2011-01-22 06:46:43 +020080 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020081 if (!skb)
82 return -ENOMEM;
83
84 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020085
Johan Hedberg02d98122010-12-13 21:07:04 +020086 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Johan Hedberga38528f2011-01-22 06:46:43 +020087 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020088
Johan Hedberga38528f2011-01-22 06:46:43 +020089 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
90 put_unaligned_le16(cmd, &ev->opcode);
91 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020092
93 if (sock_queue_rcv_skb(sk, skb) < 0)
94 kfree_skb(skb);
95
96 return 0;
97}
98
Johan Hedberga38528f2011-01-22 06:46:43 +020099static int read_version(struct sock *sk)
100{
101 struct mgmt_rp_read_version rp;
102
103 BT_DBG("sock %p", sk);
104
105 rp.version = MGMT_VERSION;
106 put_unaligned_le16(MGMT_REVISION, &rp.revision);
107
108 return cmd_complete(sk, MGMT_OP_READ_VERSION, &rp, sizeof(rp));
109}
110
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200111static int read_index_list(struct sock *sk)
112{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200113 struct mgmt_rp_read_index_list *rp;
114 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200115 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200116 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200117 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200118
119 BT_DBG("sock %p", sk);
120
121 read_lock(&hci_dev_list_lock);
122
123 count = 0;
124 list_for_each(p, &hci_dev_list) {
125 count++;
126 }
127
Johan Hedberga38528f2011-01-22 06:46:43 +0200128 rp_len = sizeof(*rp) + (2 * count);
129 rp = kmalloc(rp_len, GFP_ATOMIC);
130 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100131 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100133 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135 put_unaligned_le16(count, &rp->num_controllers);
136
137 i = 0;
138 list_for_each(p, &hci_dev_list) {
139 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200140
141 hci_del_off_timer(d);
142
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200143 set_bit(HCI_MGMT, &d->flags);
144
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200145 if (test_bit(HCI_SETUP, &d->flags))
146 continue;
147
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148 put_unaligned_le16(d->id, &rp->index[i++]);
149 BT_DBG("Added hci%u", d->id);
150 }
151
152 read_unlock(&hci_dev_list_lock);
153
Johan Hedberga38528f2011-01-22 06:46:43 +0200154 err = cmd_complete(sk, MGMT_OP_READ_INDEX_LIST, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200155
Johan Hedberga38528f2011-01-22 06:46:43 +0200156 kfree(rp);
157
158 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200159}
160
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200161static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200162{
Johan Hedberga38528f2011-01-22 06:46:43 +0200163 struct mgmt_rp_read_info rp;
164 struct mgmt_cp_read_info *cp = (void *) data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200165 struct hci_dev *hdev;
166 u16 dev_id;
Johan Hedberg03811012010-12-08 00:21:06 +0200167
168 BT_DBG("sock %p", sk);
169
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200170 if (len != 2)
171 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
172
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200173 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);
Johan Hedberga38528f2011-01-22 06:46:43 +0200178 if (!hdev)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200179 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200180
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200181 hci_del_off_timer(hdev);
182
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200183 hci_dev_lock_bh(hdev);
184
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200185 set_bit(HCI_MGMT, &hdev->flags);
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187 put_unaligned_le16(hdev->id, &rp.index);
188 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200189
Johan Hedberga38528f2011-01-22 06:46:43 +0200190 rp.powered = test_bit(HCI_UP, &hdev->flags);
191 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
192 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
193 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200194
195 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 bacpy(&rp.bdaddr, &hdev->bdaddr);
203 memcpy(rp.features, hdev->features, 8);
204 memcpy(rp.dev_class, hdev->dev_class, 3);
205 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
206 rp.hci_ver = hdev->hci_ver;
207 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200208
209 hci_dev_unlock_bh(hdev);
210 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200211
Johan Hedberga38528f2011-01-22 06:46:43 +0200212 return cmd_complete(sk, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200213}
214
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200215static void mgmt_pending_free(struct pending_cmd *cmd)
216{
217 sock_put(cmd->sk);
218 kfree(cmd->cmd);
219 kfree(cmd);
220}
221
Johan Hedberg366a0332011-02-19 12:05:55 -0300222static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
223 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200224{
225 struct pending_cmd *cmd;
226
227 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
228 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300229 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200230
231 cmd->opcode = opcode;
232 cmd->index = index;
233
234 cmd->cmd = kmalloc(len, GFP_ATOMIC);
235 if (!cmd->cmd) {
236 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300237 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200238 }
239
240 memcpy(cmd->cmd, data, len);
241
242 cmd->sk = sk;
243 sock_hold(sk);
244
245 list_add(&cmd->list, &cmd_list);
246
Johan Hedberg366a0332011-02-19 12:05:55 -0300247 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200248}
249
250static void mgmt_pending_foreach(u16 opcode, int index,
251 void (*cb)(struct pending_cmd *cmd, void *data),
252 void *data)
253{
254 struct list_head *p, *n;
255
256 list_for_each_safe(p, n, &cmd_list) {
257 struct pending_cmd *cmd;
258
259 cmd = list_entry(p, struct pending_cmd, list);
260
261 if (cmd->opcode != opcode)
262 continue;
263
264 if (index >= 0 && cmd->index != index)
265 continue;
266
267 cb(cmd, data);
268 }
269}
270
271static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
272{
273 struct list_head *p;
274
275 list_for_each(p, &cmd_list) {
276 struct pending_cmd *cmd;
277
278 cmd = list_entry(p, struct pending_cmd, list);
279
280 if (cmd->opcode != opcode)
281 continue;
282
283 if (index >= 0 && cmd->index != index)
284 continue;
285
286 return cmd;
287 }
288
289 return NULL;
290}
291
Johan Hedberg73f22f62010-12-29 16:00:25 +0200292static void mgmt_pending_remove(u16 opcode, int index)
293{
294 struct pending_cmd *cmd;
295
296 cmd = mgmt_pending_find(opcode, index);
297 if (cmd == NULL)
298 return;
299
300 list_del(&cmd->list);
301 mgmt_pending_free(cmd);
302}
303
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304static int set_powered(struct sock *sk, unsigned char *data, u16 len)
305{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200306 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200307 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300308 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200309 u16 dev_id;
Johan Hedberg366a0332011-02-19 12:05:55 -0300310 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
312 cp = (void *) data;
313 dev_id = get_unaligned_le16(&cp->index);
314
315 BT_DBG("request for hci%u", dev_id);
316
317 hdev = hci_dev_get(dev_id);
318 if (!hdev)
319 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
320
321 hci_dev_lock_bh(hdev);
322
323 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200324 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300325 err = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200326 goto failed;
327 }
328
329 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300330 err = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331 goto failed;
332 }
333
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
335 if (!cmd) {
336 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300338 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339
Johan Hedberg72a734e2010-12-30 00:38:22 +0200340 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341 queue_work(hdev->workqueue, &hdev->power_on);
342 else
343 queue_work(hdev->workqueue, &hdev->power_off);
344
Johan Hedberg366a0332011-02-19 12:05:55 -0300345 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346
347failed:
348 hci_dev_unlock_bh(hdev);
349 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300350 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200351}
352
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
354{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200355 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 u16 dev_id;
359 u8 scan;
360 int err;
361
362 cp = (void *) data;
363 dev_id = get_unaligned_le16(&cp->index);
364
365 BT_DBG("request for hci%u", dev_id);
366
367 hdev = hci_dev_get(dev_id);
368 if (!hdev)
369 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
370
371 hci_dev_lock_bh(hdev);
372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
374 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
375 goto failed;
376 }
377
378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
381 goto failed;
382 }
383
Johan Hedberg72a734e2010-12-30 00:38:22 +0200384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 test_bit(HCI_PSCAN, &hdev->flags)) {
386 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
387 goto failed;
388 }
389
Johan Hedberg366a0332011-02-19 12:05:55 -0300390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
391 if (!cmd) {
392 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
396 scan = SCAN_PAGE;
397
Johan Hedberg72a734e2010-12-30 00:38:22 +0200398 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399 scan |= SCAN_INQUIRY;
400
401 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
402 if (err < 0)
403 mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
404
405failed:
406 hci_dev_unlock_bh(hdev);
407 hci_dev_put(hdev);
408
409 return err;
410}
411
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200412static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
413{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200414 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300416 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417 u16 dev_id;
418 u8 scan;
419 int err;
420
421 cp = (void *) data;
422 dev_id = get_unaligned_le16(&cp->index);
423
424 BT_DBG("request for hci%u", dev_id);
425
426 hdev = hci_dev_get(dev_id);
427 if (!hdev)
428 return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
429
430 hci_dev_lock_bh(hdev);
431
432 if (!test_bit(HCI_UP, &hdev->flags)) {
433 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
434 goto failed;
435 }
436
437 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
438 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
439 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
440 goto failed;
441 }
442
Johan Hedberg72a734e2010-12-30 00:38:22 +0200443 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
445 goto failed;
446 }
447
Johan Hedberg366a0332011-02-19 12:05:55 -0300448 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
449 if (!cmd) {
450 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200451 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300452 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453
Johan Hedberg72a734e2010-12-30 00:38:22 +0200454 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200455 scan = SCAN_PAGE;
456 else
457 scan = 0;
458
459 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
460 if (err < 0)
461 mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
462
463failed:
464 hci_dev_unlock_bh(hdev);
465 hci_dev_put(hdev);
466
467 return err;
468}
469
Johan Hedbergc542a062011-01-26 13:11:03 +0200470static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
471{
472 struct sk_buff *skb;
473 struct mgmt_hdr *hdr;
474
475 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
476 if (!skb)
477 return -ENOMEM;
478
479 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
480
481 hdr = (void *) skb_put(skb, sizeof(*hdr));
482 hdr->opcode = cpu_to_le16(event);
483 hdr->len = cpu_to_le16(data_len);
484
485 memcpy(skb_put(skb, data_len), data, data_len);
486
487 hci_send_to_sock(NULL, skb, skip_sk);
488 kfree_skb(skb);
489
490 return 0;
491}
492
Johan Hedberg053f0212011-01-26 13:07:10 +0200493static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
494{
Johan Hedberga38528f2011-01-22 06:46:43 +0200495 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200496
Johan Hedberga38528f2011-01-22 06:46:43 +0200497 put_unaligned_le16(index, &rp.index);
498 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200499
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 return cmd_complete(sk, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200501}
502
Johan Hedbergc542a062011-01-26 13:11:03 +0200503static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
504{
505 struct mgmt_mode *cp, ev;
506 struct hci_dev *hdev;
507 u16 dev_id;
508 int err;
509
510 cp = (void *) data;
511 dev_id = get_unaligned_le16(&cp->index);
512
513 BT_DBG("request for hci%u", dev_id);
514
515 hdev = hci_dev_get(dev_id);
516 if (!hdev)
517 return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
518
519 hci_dev_lock_bh(hdev);
520
521 if (cp->val)
522 set_bit(HCI_PAIRABLE, &hdev->flags);
523 else
524 clear_bit(HCI_PAIRABLE, &hdev->flags);
525
526 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
527 if (err < 0)
528 goto failed;
529
530 put_unaligned_le16(dev_id, &ev.index);
531 ev.val = cp->val;
532
533 err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
534
535failed:
536 hci_dev_unlock_bh(hdev);
537 hci_dev_put(hdev);
538
539 return err;
540}
541
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200542static u8 get_service_classes(struct hci_dev *hdev)
543{
544 struct list_head *p;
545 u8 val = 0;
546
547 list_for_each(p, &hdev->uuids) {
548 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
549
550 val |= uuid->svc_hint;
551 }
552
553 return val;
554}
555
556static int update_class(struct hci_dev *hdev)
557{
558 u8 cod[3];
559
560 BT_DBG("%s", hdev->name);
561
562 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
563 return 0;
564
565 cod[0] = hdev->minor_class;
566 cod[1] = hdev->major_class;
567 cod[2] = get_service_classes(hdev);
568
569 if (memcmp(cod, hdev->dev_class, 3) == 0)
570 return 0;
571
572 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
573}
574
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200575static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
576{
577 struct mgmt_cp_add_uuid *cp;
578 struct hci_dev *hdev;
579 struct bt_uuid *uuid;
580 u16 dev_id;
581 int err;
582
583 cp = (void *) data;
584 dev_id = get_unaligned_le16(&cp->index);
585
586 BT_DBG("request for hci%u", dev_id);
587
588 hdev = hci_dev_get(dev_id);
589 if (!hdev)
590 return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
591
592 hci_dev_lock_bh(hdev);
593
594 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
595 if (!uuid) {
596 err = -ENOMEM;
597 goto failed;
598 }
599
600 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200601 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200602
603 list_add(&uuid->list, &hdev->uuids);
604
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200605 err = update_class(hdev);
606 if (err < 0)
607 goto failed;
608
Johan Hedberga38528f2011-01-22 06:46:43 +0200609 err = cmd_complete(sk, MGMT_OP_ADD_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200610
611failed:
612 hci_dev_unlock_bh(hdev);
613 hci_dev_put(hdev);
614
615 return err;
616}
617
618static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
619{
620 struct list_head *p, *n;
621 struct mgmt_cp_add_uuid *cp;
622 struct hci_dev *hdev;
623 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
624 u16 dev_id;
625 int err, found;
626
627 cp = (void *) data;
628 dev_id = get_unaligned_le16(&cp->index);
629
630 BT_DBG("request for hci%u", dev_id);
631
632 hdev = hci_dev_get(dev_id);
633 if (!hdev)
634 return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
635
636 hci_dev_lock_bh(hdev);
637
638 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
639 err = hci_uuids_clear(hdev);
640 goto unlock;
641 }
642
643 found = 0;
644
645 list_for_each_safe(p, n, &hdev->uuids) {
646 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
647
648 if (memcmp(match->uuid, cp->uuid, 16) != 0)
649 continue;
650
651 list_del(&match->list);
652 found++;
653 }
654
655 if (found == 0) {
656 err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
657 goto unlock;
658 }
659
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200660 err = update_class(hdev);
661 if (err < 0)
662 goto unlock;
663
Johan Hedberga38528f2011-01-22 06:46:43 +0200664 err = cmd_complete(sk, MGMT_OP_REMOVE_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200665
666unlock:
667 hci_dev_unlock_bh(hdev);
668 hci_dev_put(hdev);
669
670 return err;
671}
672
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200673static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
674{
675 struct hci_dev *hdev;
676 struct mgmt_cp_set_dev_class *cp;
677 u16 dev_id;
678 int err;
679
680 cp = (void *) data;
681 dev_id = get_unaligned_le16(&cp->index);
682
683 BT_DBG("request for hci%u", dev_id);
684
685 hdev = hci_dev_get(dev_id);
686 if (!hdev)
687 return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
688
689 hci_dev_lock_bh(hdev);
690
691 hdev->major_class = cp->major;
692 hdev->minor_class = cp->minor;
693
694 err = update_class(hdev);
695
696 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200697 err = cmd_complete(sk, MGMT_OP_SET_DEV_CLASS, &dev_id,
698 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699
700 hci_dev_unlock_bh(hdev);
701 hci_dev_put(hdev);
702
703 return err;
704}
705
706static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
707{
708 struct hci_dev *hdev;
709 struct mgmt_cp_set_service_cache *cp;
710 u16 dev_id;
711 int err;
712
713 cp = (void *) data;
714 dev_id = get_unaligned_le16(&cp->index);
715
716 hdev = hci_dev_get(dev_id);
717 if (!hdev)
718 return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
719
720 hci_dev_lock_bh(hdev);
721
722 BT_DBG("hci%u enable %d", dev_id, cp->enable);
723
724 if (cp->enable) {
725 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
726 err = 0;
727 } else {
728 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
729 err = update_class(hdev);
730 }
731
732 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200733 err = cmd_complete(sk, MGMT_OP_SET_SERVICE_CACHE, &dev_id,
734 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200735
736 hci_dev_unlock_bh(hdev);
737 hci_dev_put(hdev);
738
739 return err;
740}
741
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200742static int load_keys(struct sock *sk, unsigned char *data, u16 len)
743{
744 struct hci_dev *hdev;
745 struct mgmt_cp_load_keys *cp;
746 u16 dev_id, key_count, expected_len;
747 int i;
748
749 cp = (void *) data;
750 dev_id = get_unaligned_le16(&cp->index);
751 key_count = get_unaligned_le16(&cp->key_count);
752
753 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
754 if (expected_len != len) {
755 BT_ERR("load_keys: expected %u bytes, got %u bytes",
756 len, expected_len);
757 return -EINVAL;
758 }
759
760 hdev = hci_dev_get(dev_id);
761 if (!hdev)
762 return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
763
764 BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
765 key_count);
766
767 hci_dev_lock_bh(hdev);
768
769 hci_link_keys_clear(hdev);
770
771 set_bit(HCI_LINK_KEYS, &hdev->flags);
772
773 if (cp->debug_keys)
774 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
775 else
776 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
777
778 for (i = 0; i < key_count; i++) {
779 struct mgmt_key_info *key = &cp->keys[i];
780
781 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
782 key->pin_len);
783 }
784
785 hci_dev_unlock_bh(hdev);
786 hci_dev_put(hdev);
787
788 return 0;
789}
790
791static int remove_key(struct sock *sk, unsigned char *data, u16 len)
792{
793 struct hci_dev *hdev;
794 struct mgmt_cp_remove_key *cp;
795 struct hci_conn *conn;
796 u16 dev_id;
797 int err;
798
799 cp = (void *) data;
800 dev_id = get_unaligned_le16(&cp->index);
801
802 hdev = hci_dev_get(dev_id);
803 if (!hdev)
804 return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
805
806 hci_dev_lock_bh(hdev);
807
808 err = hci_remove_link_key(hdev, &cp->bdaddr);
809 if (err < 0) {
810 err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
811 goto unlock;
812 }
813
814 err = 0;
815
816 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
817 goto unlock;
818
819 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
820 if (conn) {
821 struct hci_cp_disconnect dc;
822
823 put_unaligned_le16(conn->handle, &dc.handle);
824 dc.reason = 0x13; /* Remote User Terminated Connection */
825 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
826 }
827
828unlock:
829 hci_dev_unlock_bh(hdev);
830 hci_dev_put(hdev);
831
832 return err;
833}
834
Johan Hedberg8962ee72011-01-20 12:40:27 +0200835static int disconnect(struct sock *sk, unsigned char *data, u16 len)
836{
837 struct hci_dev *hdev;
838 struct mgmt_cp_disconnect *cp;
839 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300840 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200841 struct hci_conn *conn;
842 u16 dev_id;
843 int err;
844
845 BT_DBG("");
846
847 cp = (void *) data;
848 dev_id = get_unaligned_le16(&cp->index);
849
850 hdev = hci_dev_get(dev_id);
851 if (!hdev)
852 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
853
854 hci_dev_lock_bh(hdev);
855
856 if (!test_bit(HCI_UP, &hdev->flags)) {
857 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
858 goto failed;
859 }
860
861 if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
862 err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
863 goto failed;
864 }
865
866 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
867 if (!conn) {
868 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
869 goto failed;
870 }
871
Johan Hedberg366a0332011-02-19 12:05:55 -0300872 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, dev_id, data, len);
873 if (!cmd) {
874 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200875 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300876 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200877
878 put_unaligned_le16(conn->handle, &dc.handle);
879 dc.reason = 0x13; /* Remote User Terminated Connection */
880
881 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
882 if (err < 0)
883 mgmt_pending_remove(MGMT_OP_DISCONNECT, dev_id);
884
885failed:
886 hci_dev_unlock_bh(hdev);
887 hci_dev_put(hdev);
888
889 return err;
890}
891
Johan Hedberg2784eb42011-01-21 13:56:35 +0200892static int get_connections(struct sock *sk, unsigned char *data, u16 len)
893{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200894 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200895 struct mgmt_rp_get_connections *rp;
896 struct hci_dev *hdev;
897 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200898 size_t rp_len;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200899 u16 dev_id, count;
900 int i, err;
901
902 BT_DBG("");
903
904 cp = (void *) data;
905 dev_id = get_unaligned_le16(&cp->index);
906
907 hdev = hci_dev_get(dev_id);
908 if (!hdev)
909 return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
910
911 hci_dev_lock_bh(hdev);
912
913 count = 0;
914 list_for_each(p, &hdev->conn_hash.list) {
915 count++;
916 }
917
Johan Hedberga38528f2011-01-22 06:46:43 +0200918 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
919 rp = kmalloc(rp_len, GFP_ATOMIC);
920 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200921 err = -ENOMEM;
922 goto unlock;
923 }
924
Johan Hedberg2784eb42011-01-21 13:56:35 +0200925 put_unaligned_le16(dev_id, &rp->index);
926 put_unaligned_le16(count, &rp->conn_count);
927
928 read_lock(&hci_dev_list_lock);
929
930 i = 0;
931 list_for_each(p, &hdev->conn_hash.list) {
932 struct hci_conn *c = list_entry(p, struct hci_conn, list);
933
934 bacpy(&rp->conn[i++], &c->dst);
935 }
936
937 read_unlock(&hci_dev_list_lock);
938
Johan Hedberga38528f2011-01-22 06:46:43 +0200939 err = cmd_complete(sk, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200940
941unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200942 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200943 hci_dev_unlock_bh(hdev);
944 hci_dev_put(hdev);
945 return err;
946}
947
Johan Hedberg980e1a52011-01-22 06:10:07 +0200948static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
949{
950 struct hci_dev *hdev;
951 struct mgmt_cp_pin_code_reply *cp;
952 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300953 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200954 u16 dev_id;
955 int 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_DISCONNECT, ENODEV);
965
966 hci_dev_lock_bh(hdev);
967
968 if (!test_bit(HCI_UP, &hdev->flags)) {
969 err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
970 goto failed;
971 }
972
Johan Hedberg366a0332011-02-19 12:05:55 -0300973 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
974 if (!cmd) {
975 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200976 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300977 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200978
979 bacpy(&reply.bdaddr, &cp->bdaddr);
980 reply.pin_len = cp->pin_len;
981 memcpy(reply.pin_code, cp->pin_code, 16);
982
983 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
984 if (err < 0)
985 mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
986
987failed:
988 hci_dev_unlock_bh(hdev);
989 hci_dev_put(hdev);
990
991 return err;
992}
993
994static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
995{
996 struct hci_dev *hdev;
997 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -0300998 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200999 u16 dev_id;
1000 int err;
1001
1002 BT_DBG("");
1003
1004 cp = (void *) data;
1005 dev_id = get_unaligned_le16(&cp->index);
1006
1007 hdev = hci_dev_get(dev_id);
1008 if (!hdev)
1009 return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
1010
1011 hci_dev_lock_bh(hdev);
1012
1013 if (!test_bit(HCI_UP, &hdev->flags)) {
1014 err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
1015 goto failed;
1016 }
1017
Johan Hedberg366a0332011-02-19 12:05:55 -03001018 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001019 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001020 if (!cmd) {
1021 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001022 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001023 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001024
1025 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1026 &cp->bdaddr);
1027 if (err < 0)
1028 mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
1029
1030failed:
1031 hci_dev_unlock_bh(hdev);
1032 hci_dev_put(hdev);
1033
1034 return err;
1035}
1036
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001037static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
1038{
1039 struct hci_dev *hdev;
1040 struct mgmt_cp_set_io_capability *cp;
1041 u16 dev_id;
1042
1043 BT_DBG("");
1044
1045 cp = (void *) data;
1046 dev_id = get_unaligned_le16(&cp->index);
1047
1048 hdev = hci_dev_get(dev_id);
1049 if (!hdev)
1050 return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
1051
1052 hci_dev_lock_bh(hdev);
1053
1054 hdev->io_capability = cp->io_capability;
1055
1056 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1057 hdev->io_capability);
1058
1059 hci_dev_unlock_bh(hdev);
1060 hci_dev_put(hdev);
1061
1062 return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY,
1063 &dev_id, sizeof(dev_id));
1064}
1065
Johan Hedberg03811012010-12-08 00:21:06 +02001066int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1067{
1068 unsigned char *buf;
1069 struct mgmt_hdr *hdr;
1070 u16 opcode, len;
1071 int err;
1072
1073 BT_DBG("got %zu bytes", msglen);
1074
1075 if (msglen < sizeof(*hdr))
1076 return -EINVAL;
1077
1078 buf = kmalloc(msglen, GFP_ATOMIC);
1079 if (!buf)
1080 return -ENOMEM;
1081
1082 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1083 err = -EFAULT;
1084 goto done;
1085 }
1086
1087 hdr = (struct mgmt_hdr *) buf;
1088 opcode = get_unaligned_le16(&hdr->opcode);
1089 len = get_unaligned_le16(&hdr->len);
1090
1091 if (len != msglen - sizeof(*hdr)) {
1092 err = -EINVAL;
1093 goto done;
1094 }
1095
1096 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001097 case MGMT_OP_READ_VERSION:
1098 err = read_version(sk);
1099 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001100 case MGMT_OP_READ_INDEX_LIST:
1101 err = read_index_list(sk);
1102 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001103 case MGMT_OP_READ_INFO:
1104 err = read_controller_info(sk, buf + sizeof(*hdr), len);
1105 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001106 case MGMT_OP_SET_POWERED:
1107 err = set_powered(sk, buf + sizeof(*hdr), len);
1108 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001109 case MGMT_OP_SET_DISCOVERABLE:
1110 err = set_discoverable(sk, buf + sizeof(*hdr), len);
1111 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001112 case MGMT_OP_SET_CONNECTABLE:
1113 err = set_connectable(sk, buf + sizeof(*hdr), len);
1114 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001115 case MGMT_OP_SET_PAIRABLE:
1116 err = set_pairable(sk, buf + sizeof(*hdr), len);
1117 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001118 case MGMT_OP_ADD_UUID:
1119 err = add_uuid(sk, buf + sizeof(*hdr), len);
1120 break;
1121 case MGMT_OP_REMOVE_UUID:
1122 err = remove_uuid(sk, buf + sizeof(*hdr), len);
1123 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001124 case MGMT_OP_SET_DEV_CLASS:
1125 err = set_dev_class(sk, buf + sizeof(*hdr), len);
1126 break;
1127 case MGMT_OP_SET_SERVICE_CACHE:
1128 err = set_service_cache(sk, buf + sizeof(*hdr), len);
1129 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001130 case MGMT_OP_LOAD_KEYS:
1131 err = load_keys(sk, buf + sizeof(*hdr), len);
1132 break;
1133 case MGMT_OP_REMOVE_KEY:
1134 err = remove_key(sk, buf + sizeof(*hdr), len);
1135 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001136 case MGMT_OP_DISCONNECT:
1137 err = disconnect(sk, buf + sizeof(*hdr), len);
1138 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001139 case MGMT_OP_GET_CONNECTIONS:
1140 err = get_connections(sk, buf + sizeof(*hdr), len);
1141 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001142 case MGMT_OP_PIN_CODE_REPLY:
1143 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1144 break;
1145 case MGMT_OP_PIN_CODE_NEG_REPLY:
1146 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1147 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001148 case MGMT_OP_SET_IO_CAPABILITY:
1149 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1150 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001151 default:
1152 BT_DBG("Unknown op %u", opcode);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001153 err = cmd_status(sk, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001154 break;
1155 }
1156
Johan Hedberge41d8b42010-12-13 21:07:03 +02001157 if (err < 0)
1158 goto done;
1159
Johan Hedberg03811012010-12-08 00:21:06 +02001160 err = msglen;
1161
1162done:
1163 kfree(buf);
1164 return err;
1165}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001166
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001167int mgmt_index_added(u16 index)
1168{
1169 struct mgmt_ev_index_added ev;
1170
1171 put_unaligned_le16(index, &ev.index);
1172
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001173 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001174}
1175
1176int mgmt_index_removed(u16 index)
1177{
1178 struct mgmt_ev_index_added ev;
1179
1180 put_unaligned_le16(index, &ev.index);
1181
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
1183}
1184
Johan Hedberg73f22f62010-12-29 16:00:25 +02001185struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001186 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 struct sock *sk;
1188};
1189
Johan Hedberg72a734e2010-12-30 00:38:22 +02001190static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001192 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001193 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194
Johan Hedberg72a734e2010-12-30 00:38:22 +02001195 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196 return;
1197
Johan Hedberg053f0212011-01-26 13:07:10 +02001198 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199
1200 list_del(&cmd->list);
1201
1202 if (match->sk == NULL) {
1203 match->sk = cmd->sk;
1204 sock_hold(match->sk);
1205 }
1206
1207 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001208}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001209
1210int mgmt_powered(u16 index, u8 powered)
1211{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001212 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001213 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001215
Johan Hedberg72a734e2010-12-30 00:38:22 +02001216 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001217
Johan Hedberg72a734e2010-12-30 00:38:22 +02001218 put_unaligned_le16(index, &ev.index);
1219 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220
1221 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
1222
1223 if (match.sk)
1224 sock_put(match.sk);
1225
1226 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001227}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001228
Johan Hedberg73f22f62010-12-29 16:00:25 +02001229int mgmt_discoverable(u16 index, u8 discoverable)
1230{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001231 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001232 struct cmd_lookup match = { discoverable, NULL };
1233 int ret;
1234
Johan Hedberg73f22f62010-12-29 16:00:25 +02001235 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001236 mode_rsp, &match);
1237
1238 put_unaligned_le16(index, &ev.index);
1239 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001240
1241 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
1242
1243 if (match.sk)
1244 sock_put(match.sk);
1245
1246 return ret;
1247}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001248
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001249int mgmt_connectable(u16 index, u8 connectable)
1250{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001251 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001252 struct cmd_lookup match = { connectable, NULL };
1253 int ret;
1254
Johan Hedberg72a734e2010-12-30 00:38:22 +02001255 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001256
Johan Hedberg72a734e2010-12-30 00:38:22 +02001257 put_unaligned_le16(index, &ev.index);
1258 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001259
1260 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
1261
1262 if (match.sk)
1263 sock_put(match.sk);
1264
1265 return ret;
1266}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001267
1268int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1269{
1270 struct mgmt_ev_new_key ev;
1271
1272 memset(&ev, 0, sizeof(ev));
1273
1274 put_unaligned_le16(index, &ev.index);
1275
1276 bacpy(&ev.key.bdaddr, &key->bdaddr);
1277 ev.key.type = key->type;
1278 memcpy(ev.key.val, key->val, 16);
1279 ev.key.pin_len = key->pin_len;
1280 ev.old_key_type = old_key_type;
1281
1282 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1283}
Johan Hedbergf7520542011-01-20 12:34:39 +02001284
1285int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1286{
1287 struct mgmt_ev_connected ev;
1288
1289 put_unaligned_le16(index, &ev.index);
1290 bacpy(&ev.bdaddr, bdaddr);
1291
1292 return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
1293}
1294
Johan Hedberg8962ee72011-01-20 12:40:27 +02001295static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1296{
1297 struct mgmt_cp_disconnect *cp = cmd->cmd;
1298 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001299 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001300
Johan Hedberga38528f2011-01-22 06:46:43 +02001301 put_unaligned_le16(cmd->index, &rp.index);
1302 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001303
Johan Hedberga38528f2011-01-22 06:46:43 +02001304 cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001305
1306 *sk = cmd->sk;
1307 sock_hold(*sk);
1308
1309 list_del(&cmd->list);
1310 mgmt_pending_free(cmd);
1311}
1312
Johan Hedbergf7520542011-01-20 12:34:39 +02001313int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1314{
1315 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001316 struct sock *sk = NULL;
1317 int err;
1318
1319 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001320
1321 put_unaligned_le16(index, &ev.index);
1322 bacpy(&ev.bdaddr, bdaddr);
1323
Johan Hedberg8962ee72011-01-20 12:40:27 +02001324 err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
1325
1326 if (sk)
1327 sock_put(sk);
1328
1329 return err;
1330}
1331
1332int mgmt_disconnect_failed(u16 index)
1333{
1334 struct pending_cmd *cmd;
1335 int err;
1336
1337 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1338 if (!cmd)
1339 return -ENOENT;
1340
1341 err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
1342
1343 list_del(&cmd->list);
1344 mgmt_pending_free(cmd);
1345
1346 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001347}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001348
1349int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1350{
1351 struct mgmt_ev_connect_failed ev;
1352
1353 put_unaligned_le16(index, &ev.index);
1354 bacpy(&ev.bdaddr, bdaddr);
1355 ev.status = status;
1356
1357 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1358}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001359
1360int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1361{
1362 struct mgmt_ev_pin_code_request ev;
1363
1364 put_unaligned_le16(index, &ev.index);
1365 bacpy(&ev.bdaddr, bdaddr);
1366
1367 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1368}
1369
1370int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1371{
1372 struct pending_cmd *cmd;
1373 int err;
1374
1375 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1376 if (!cmd)
1377 return -ENOENT;
1378
1379 if (status != 0)
1380 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
1381 else
1382 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
1383 bdaddr, sizeof(*bdaddr));
1384
1385 list_del(&cmd->list);
1386 mgmt_pending_free(cmd);
1387
1388 return err;
1389}
1390
1391int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1392{
1393 struct pending_cmd *cmd;
1394 int err;
1395
1396 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1397 if (!cmd)
1398 return -ENOENT;
1399
1400 if (status != 0)
1401 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
1402 else
1403 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1404 bdaddr, sizeof(*bdaddr));
1405
1406 list_del(&cmd->list);
1407 mgmt_pending_free(cmd);
1408
1409 return err;
1410}