blob: d7fc54dcbc9e1f074dadbf9af73862326d7372c5 [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;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
44LIST_HEAD(cmd_list);
45
Johan Hedbergf7b64e692010-12-13 21:07:06 +020046static int cmd_status(struct sock *sk, u16 cmd, u8 status)
47{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
52 BT_DBG("sock %p", sk);
53
54 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
55 if (!skb)
56 return -ENOMEM;
57
58 hdr = (void *) skb_put(skb, sizeof(*hdr));
59
60 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
61 hdr->len = cpu_to_le16(sizeof(*ev));
62
63 ev = (void *) skb_put(skb, sizeof(*ev));
64 ev->status = status;
65 put_unaligned_le16(cmd, &ev->opcode);
66
67 if (sock_queue_rcv_skb(sk, skb) < 0)
68 kfree_skb(skb);
69
70 return 0;
71}
72
Johan Hedberga38528f2011-01-22 06:46:43 +020073static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020074{
75 struct sk_buff *skb;
76 struct mgmt_hdr *hdr;
77 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020078
79 BT_DBG("sock %p", sk);
80
Johan Hedberga38528f2011-01-22 06:46:43 +020081 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020082 if (!skb)
83 return -ENOMEM;
84
85 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020086
Johan Hedberg02d98122010-12-13 21:07:04 +020087 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Johan Hedberga38528f2011-01-22 06:46:43 +020088 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020089
Johan Hedberga38528f2011-01-22 06:46:43 +020090 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
91 put_unaligned_le16(cmd, &ev->opcode);
92 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020093
94 if (sock_queue_rcv_skb(sk, skb) < 0)
95 kfree_skb(skb);
96
97 return 0;
98}
99
Johan Hedberga38528f2011-01-22 06:46:43 +0200100static int read_version(struct sock *sk)
101{
102 struct mgmt_rp_read_version rp;
103
104 BT_DBG("sock %p", sk);
105
106 rp.version = MGMT_VERSION;
107 put_unaligned_le16(MGMT_REVISION, &rp.revision);
108
109 return cmd_complete(sk, MGMT_OP_READ_VERSION, &rp, sizeof(rp));
110}
111
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200112static int read_index_list(struct sock *sk)
113{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200114 struct mgmt_rp_read_index_list *rp;
115 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200116 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200117 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200118 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200119
120 BT_DBG("sock %p", sk);
121
122 read_lock(&hci_dev_list_lock);
123
124 count = 0;
125 list_for_each(p, &hci_dev_list) {
126 count++;
127 }
128
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 rp_len = sizeof(*rp) + (2 * count);
130 rp = kmalloc(rp_len, GFP_ATOMIC);
131 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100132 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200133 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100134 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200136 put_unaligned_le16(count, &rp->num_controllers);
137
138 i = 0;
139 list_for_each(p, &hci_dev_list) {
140 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200141
142 hci_del_off_timer(d);
143
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200144 set_bit(HCI_MGMT, &d->flags);
145
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200146 if (test_bit(HCI_SETUP, &d->flags))
147 continue;
148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(d->id, &rp->index[i++]);
150 BT_DBG("Added hci%u", d->id);
151 }
152
153 read_unlock(&hci_dev_list_lock);
154
Johan Hedberga38528f2011-01-22 06:46:43 +0200155 err = cmd_complete(sk, MGMT_OP_READ_INDEX_LIST, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156
Johan Hedberga38528f2011-01-22 06:46:43 +0200157 kfree(rp);
158
159 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160}
161
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200162static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200163{
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 struct mgmt_rp_read_info rp;
165 struct mgmt_cp_read_info *cp = (void *) data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200166 struct hci_dev *hdev;
167 u16 dev_id;
Johan Hedberg03811012010-12-08 00:21:06 +0200168
169 BT_DBG("sock %p", sk);
170
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200171 if (len != 2)
172 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
173
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200174 dev_id = get_unaligned_le16(&cp->index);
175
176 BT_DBG("request for hci%u", dev_id);
177
178 hdev = hci_dev_get(dev_id);
Johan Hedberga38528f2011-01-22 06:46:43 +0200179 if (!hdev)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200180 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200181
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200182 hci_del_off_timer(hdev);
183
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200184 hci_dev_lock_bh(hdev);
185
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200186 set_bit(HCI_MGMT, &hdev->flags);
187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 put_unaligned_le16(hdev->id, &rp.index);
189 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.powered = test_bit(HCI_UP, &hdev->flags);
192 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
193 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
194 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195
196 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200197 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 bacpy(&rp.bdaddr, &hdev->bdaddr);
204 memcpy(rp.features, hdev->features, 8);
205 memcpy(rp.dev_class, hdev->dev_class, 3);
206 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
207 rp.hci_ver = hdev->hci_ver;
208 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200209
210 hci_dev_unlock_bh(hdev);
211 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200212
Johan Hedberga38528f2011-01-22 06:46:43 +0200213 return cmd_complete(sk, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200214}
215
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200216static void mgmt_pending_free(struct pending_cmd *cmd)
217{
218 sock_put(cmd->sk);
219 kfree(cmd->cmd);
220 kfree(cmd);
221}
222
Johan Hedberg366a0332011-02-19 12:05:55 -0300223static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
224 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200225{
226 struct pending_cmd *cmd;
227
228 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
229 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300230 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200231
232 cmd->opcode = opcode;
233 cmd->index = index;
234
235 cmd->cmd = kmalloc(len, GFP_ATOMIC);
236 if (!cmd->cmd) {
237 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300238 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 }
240
241 memcpy(cmd->cmd, data, len);
242
243 cmd->sk = sk;
244 sock_hold(sk);
245
246 list_add(&cmd->list, &cmd_list);
247
Johan Hedberg366a0332011-02-19 12:05:55 -0300248 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200249}
250
251static void mgmt_pending_foreach(u16 opcode, int index,
252 void (*cb)(struct pending_cmd *cmd, void *data),
253 void *data)
254{
255 struct list_head *p, *n;
256
257 list_for_each_safe(p, n, &cmd_list) {
258 struct pending_cmd *cmd;
259
260 cmd = list_entry(p, struct pending_cmd, list);
261
262 if (cmd->opcode != opcode)
263 continue;
264
265 if (index >= 0 && cmd->index != index)
266 continue;
267
268 cb(cmd, data);
269 }
270}
271
272static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
273{
274 struct list_head *p;
275
276 list_for_each(p, &cmd_list) {
277 struct pending_cmd *cmd;
278
279 cmd = list_entry(p, struct pending_cmd, list);
280
281 if (cmd->opcode != opcode)
282 continue;
283
284 if (index >= 0 && cmd->index != index)
285 continue;
286
287 return cmd;
288 }
289
290 return NULL;
291}
292
Johan Hedberg73f22f62010-12-29 16:00:25 +0200293static void mgmt_pending_remove(u16 opcode, int index)
294{
295 struct pending_cmd *cmd;
296
297 cmd = mgmt_pending_find(opcode, index);
298 if (cmd == NULL)
299 return;
300
301 list_del(&cmd->list);
302 mgmt_pending_free(cmd);
303}
304
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305static int set_powered(struct sock *sk, unsigned char *data, u16 len)
306{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200307 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300309 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310 u16 dev_id;
Johan Hedberg366a0332011-02-19 12:05:55 -0300311 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
313 cp = (void *) data;
314 dev_id = get_unaligned_le16(&cp->index);
315
316 BT_DBG("request for hci%u", dev_id);
317
318 hdev = hci_dev_get(dev_id);
319 if (!hdev)
320 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
321
322 hci_dev_lock_bh(hdev);
323
324 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200325 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300326 err = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200327 goto failed;
328 }
329
330 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300331 err = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 goto failed;
333 }
334
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
336 if (!cmd) {
337 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300339 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340
Johan Hedberg72a734e2010-12-30 00:38:22 +0200341 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200342 queue_work(hdev->workqueue, &hdev->power_on);
343 else
344 queue_work(hdev->workqueue, &hdev->power_off);
345
Johan Hedberg366a0332011-02-19 12:05:55 -0300346 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200347
348failed:
349 hci_dev_unlock_bh(hdev);
350 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300351 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352}
353
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
355{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200356 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300358 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200359 u16 dev_id;
360 u8 scan;
361 int err;
362
363 cp = (void *) data;
364 dev_id = get_unaligned_le16(&cp->index);
365
366 BT_DBG("request for hci%u", dev_id);
367
368 hdev = hci_dev_get(dev_id);
369 if (!hdev)
370 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
371
372 hci_dev_lock_bh(hdev);
373
374 if (!test_bit(HCI_UP, &hdev->flags)) {
375 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
376 goto failed;
377 }
378
379 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200380 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
382 goto failed;
383 }
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 test_bit(HCI_PSCAN, &hdev->flags)) {
387 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
388 goto failed;
389 }
390
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
392 if (!cmd) {
393 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396
397 scan = SCAN_PAGE;
398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400 scan |= SCAN_INQUIRY;
401
402 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
403 if (err < 0)
404 mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
405
406failed:
407 hci_dev_unlock_bh(hdev);
408 hci_dev_put(hdev);
409
410 return err;
411}
412
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
414{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200415 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200416 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300417 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418 u16 dev_id;
419 u8 scan;
420 int err;
421
422 cp = (void *) data;
423 dev_id = get_unaligned_le16(&cp->index);
424
425 BT_DBG("request for hci%u", dev_id);
426
427 hdev = hci_dev_get(dev_id);
428 if (!hdev)
429 return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
430
431 hci_dev_lock_bh(hdev);
432
433 if (!test_bit(HCI_UP, &hdev->flags)) {
434 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
435 goto failed;
436 }
437
438 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
439 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
440 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
441 goto failed;
442 }
443
Johan Hedberg72a734e2010-12-30 00:38:22 +0200444 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200445 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
446 goto failed;
447 }
448
Johan Hedberg366a0332011-02-19 12:05:55 -0300449 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
450 if (!cmd) {
451 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300453 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454
Johan Hedberg72a734e2010-12-30 00:38:22 +0200455 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456 scan = SCAN_PAGE;
457 else
458 scan = 0;
459
460 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
461 if (err < 0)
462 mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
463
464failed:
465 hci_dev_unlock_bh(hdev);
466 hci_dev_put(hdev);
467
468 return err;
469}
470
Johan Hedbergc542a062011-01-26 13:11:03 +0200471static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
472{
473 struct sk_buff *skb;
474 struct mgmt_hdr *hdr;
475
476 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
477 if (!skb)
478 return -ENOMEM;
479
480 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
481
482 hdr = (void *) skb_put(skb, sizeof(*hdr));
483 hdr->opcode = cpu_to_le16(event);
484 hdr->len = cpu_to_le16(data_len);
485
486 memcpy(skb_put(skb, data_len), data, data_len);
487
488 hci_send_to_sock(NULL, skb, skip_sk);
489 kfree_skb(skb);
490
491 return 0;
492}
493
Johan Hedberg053f0212011-01-26 13:07:10 +0200494static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
495{
Johan Hedberga38528f2011-01-22 06:46:43 +0200496 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200497
Johan Hedberga38528f2011-01-22 06:46:43 +0200498 put_unaligned_le16(index, &rp.index);
499 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200500
Johan Hedberga38528f2011-01-22 06:46:43 +0200501 return cmd_complete(sk, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200502}
503
Johan Hedbergc542a062011-01-26 13:11:03 +0200504static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
505{
506 struct mgmt_mode *cp, ev;
507 struct hci_dev *hdev;
508 u16 dev_id;
509 int err;
510
511 cp = (void *) data;
512 dev_id = get_unaligned_le16(&cp->index);
513
514 BT_DBG("request for hci%u", dev_id);
515
516 hdev = hci_dev_get(dev_id);
517 if (!hdev)
518 return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
519
520 hci_dev_lock_bh(hdev);
521
522 if (cp->val)
523 set_bit(HCI_PAIRABLE, &hdev->flags);
524 else
525 clear_bit(HCI_PAIRABLE, &hdev->flags);
526
527 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
528 if (err < 0)
529 goto failed;
530
531 put_unaligned_le16(dev_id, &ev.index);
532 ev.val = cp->val;
533
534 err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
535
536failed:
537 hci_dev_unlock_bh(hdev);
538 hci_dev_put(hdev);
539
540 return err;
541}
542
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200543static u8 get_service_classes(struct hci_dev *hdev)
544{
545 struct list_head *p;
546 u8 val = 0;
547
548 list_for_each(p, &hdev->uuids) {
549 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
550
551 val |= uuid->svc_hint;
552 }
553
554 return val;
555}
556
557static int update_class(struct hci_dev *hdev)
558{
559 u8 cod[3];
560
561 BT_DBG("%s", hdev->name);
562
563 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
564 return 0;
565
566 cod[0] = hdev->minor_class;
567 cod[1] = hdev->major_class;
568 cod[2] = get_service_classes(hdev);
569
570 if (memcmp(cod, hdev->dev_class, 3) == 0)
571 return 0;
572
573 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
574}
575
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200576static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
577{
578 struct mgmt_cp_add_uuid *cp;
579 struct hci_dev *hdev;
580 struct bt_uuid *uuid;
581 u16 dev_id;
582 int err;
583
584 cp = (void *) data;
585 dev_id = get_unaligned_le16(&cp->index);
586
587 BT_DBG("request for hci%u", dev_id);
588
589 hdev = hci_dev_get(dev_id);
590 if (!hdev)
591 return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
592
593 hci_dev_lock_bh(hdev);
594
595 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
596 if (!uuid) {
597 err = -ENOMEM;
598 goto failed;
599 }
600
601 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200602 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200603
604 list_add(&uuid->list, &hdev->uuids);
605
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200606 err = update_class(hdev);
607 if (err < 0)
608 goto failed;
609
Johan Hedberga38528f2011-01-22 06:46:43 +0200610 err = cmd_complete(sk, MGMT_OP_ADD_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200611
612failed:
613 hci_dev_unlock_bh(hdev);
614 hci_dev_put(hdev);
615
616 return err;
617}
618
619static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
620{
621 struct list_head *p, *n;
622 struct mgmt_cp_add_uuid *cp;
623 struct hci_dev *hdev;
624 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
625 u16 dev_id;
626 int err, found;
627
628 cp = (void *) data;
629 dev_id = get_unaligned_le16(&cp->index);
630
631 BT_DBG("request for hci%u", dev_id);
632
633 hdev = hci_dev_get(dev_id);
634 if (!hdev)
635 return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
636
637 hci_dev_lock_bh(hdev);
638
639 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
640 err = hci_uuids_clear(hdev);
641 goto unlock;
642 }
643
644 found = 0;
645
646 list_for_each_safe(p, n, &hdev->uuids) {
647 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
648
649 if (memcmp(match->uuid, cp->uuid, 16) != 0)
650 continue;
651
652 list_del(&match->list);
653 found++;
654 }
655
656 if (found == 0) {
657 err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
658 goto unlock;
659 }
660
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200661 err = update_class(hdev);
662 if (err < 0)
663 goto unlock;
664
Johan Hedberga38528f2011-01-22 06:46:43 +0200665 err = cmd_complete(sk, MGMT_OP_REMOVE_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200666
667unlock:
668 hci_dev_unlock_bh(hdev);
669 hci_dev_put(hdev);
670
671 return err;
672}
673
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200674static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
675{
676 struct hci_dev *hdev;
677 struct mgmt_cp_set_dev_class *cp;
678 u16 dev_id;
679 int err;
680
681 cp = (void *) data;
682 dev_id = get_unaligned_le16(&cp->index);
683
684 BT_DBG("request for hci%u", dev_id);
685
686 hdev = hci_dev_get(dev_id);
687 if (!hdev)
688 return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
689
690 hci_dev_lock_bh(hdev);
691
692 hdev->major_class = cp->major;
693 hdev->minor_class = cp->minor;
694
695 err = update_class(hdev);
696
697 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200698 err = cmd_complete(sk, MGMT_OP_SET_DEV_CLASS, &dev_id,
699 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200700
701 hci_dev_unlock_bh(hdev);
702 hci_dev_put(hdev);
703
704 return err;
705}
706
707static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
708{
709 struct hci_dev *hdev;
710 struct mgmt_cp_set_service_cache *cp;
711 u16 dev_id;
712 int err;
713
714 cp = (void *) data;
715 dev_id = get_unaligned_le16(&cp->index);
716
717 hdev = hci_dev_get(dev_id);
718 if (!hdev)
719 return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
720
721 hci_dev_lock_bh(hdev);
722
723 BT_DBG("hci%u enable %d", dev_id, cp->enable);
724
725 if (cp->enable) {
726 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
727 err = 0;
728 } else {
729 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
730 err = update_class(hdev);
731 }
732
733 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200734 err = cmd_complete(sk, MGMT_OP_SET_SERVICE_CACHE, &dev_id,
735 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200736
737 hci_dev_unlock_bh(hdev);
738 hci_dev_put(hdev);
739
740 return err;
741}
742
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200743static int load_keys(struct sock *sk, unsigned char *data, u16 len)
744{
745 struct hci_dev *hdev;
746 struct mgmt_cp_load_keys *cp;
747 u16 dev_id, key_count, expected_len;
748 int i;
749
750 cp = (void *) data;
751 dev_id = get_unaligned_le16(&cp->index);
752 key_count = get_unaligned_le16(&cp->key_count);
753
754 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
755 if (expected_len != len) {
756 BT_ERR("load_keys: expected %u bytes, got %u bytes",
757 len, expected_len);
758 return -EINVAL;
759 }
760
761 hdev = hci_dev_get(dev_id);
762 if (!hdev)
763 return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
764
765 BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
766 key_count);
767
768 hci_dev_lock_bh(hdev);
769
770 hci_link_keys_clear(hdev);
771
772 set_bit(HCI_LINK_KEYS, &hdev->flags);
773
774 if (cp->debug_keys)
775 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
776 else
777 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
778
779 for (i = 0; i < key_count; i++) {
780 struct mgmt_key_info *key = &cp->keys[i];
781
782 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
783 key->pin_len);
784 }
785
786 hci_dev_unlock_bh(hdev);
787 hci_dev_put(hdev);
788
789 return 0;
790}
791
792static int remove_key(struct sock *sk, unsigned char *data, u16 len)
793{
794 struct hci_dev *hdev;
795 struct mgmt_cp_remove_key *cp;
796 struct hci_conn *conn;
797 u16 dev_id;
798 int err;
799
800 cp = (void *) data;
801 dev_id = get_unaligned_le16(&cp->index);
802
803 hdev = hci_dev_get(dev_id);
804 if (!hdev)
805 return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
806
807 hci_dev_lock_bh(hdev);
808
809 err = hci_remove_link_key(hdev, &cp->bdaddr);
810 if (err < 0) {
811 err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
812 goto unlock;
813 }
814
815 err = 0;
816
817 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
818 goto unlock;
819
820 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
821 if (conn) {
822 struct hci_cp_disconnect dc;
823
824 put_unaligned_le16(conn->handle, &dc.handle);
825 dc.reason = 0x13; /* Remote User Terminated Connection */
826 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
827 }
828
829unlock:
830 hci_dev_unlock_bh(hdev);
831 hci_dev_put(hdev);
832
833 return err;
834}
835
Johan Hedberg8962ee72011-01-20 12:40:27 +0200836static int disconnect(struct sock *sk, unsigned char *data, u16 len)
837{
838 struct hci_dev *hdev;
839 struct mgmt_cp_disconnect *cp;
840 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300841 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200842 struct hci_conn *conn;
843 u16 dev_id;
844 int err;
845
846 BT_DBG("");
847
848 cp = (void *) data;
849 dev_id = get_unaligned_le16(&cp->index);
850
851 hdev = hci_dev_get(dev_id);
852 if (!hdev)
853 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
854
855 hci_dev_lock_bh(hdev);
856
857 if (!test_bit(HCI_UP, &hdev->flags)) {
858 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
859 goto failed;
860 }
861
862 if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
863 err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
864 goto failed;
865 }
866
867 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
868 if (!conn) {
869 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
870 goto failed;
871 }
872
Johan Hedberg366a0332011-02-19 12:05:55 -0300873 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, dev_id, data, len);
874 if (!cmd) {
875 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200876 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300877 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200878
879 put_unaligned_le16(conn->handle, &dc.handle);
880 dc.reason = 0x13; /* Remote User Terminated Connection */
881
882 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
883 if (err < 0)
884 mgmt_pending_remove(MGMT_OP_DISCONNECT, dev_id);
885
886failed:
887 hci_dev_unlock_bh(hdev);
888 hci_dev_put(hdev);
889
890 return err;
891}
892
Johan Hedberg2784eb42011-01-21 13:56:35 +0200893static int get_connections(struct sock *sk, unsigned char *data, u16 len)
894{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200895 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200896 struct mgmt_rp_get_connections *rp;
897 struct hci_dev *hdev;
898 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200899 size_t rp_len;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200900 u16 dev_id, count;
901 int i, err;
902
903 BT_DBG("");
904
905 cp = (void *) data;
906 dev_id = get_unaligned_le16(&cp->index);
907
908 hdev = hci_dev_get(dev_id);
909 if (!hdev)
910 return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
911
912 hci_dev_lock_bh(hdev);
913
914 count = 0;
915 list_for_each(p, &hdev->conn_hash.list) {
916 count++;
917 }
918
Johan Hedberga38528f2011-01-22 06:46:43 +0200919 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
920 rp = kmalloc(rp_len, GFP_ATOMIC);
921 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200922 err = -ENOMEM;
923 goto unlock;
924 }
925
Johan Hedberg2784eb42011-01-21 13:56:35 +0200926 put_unaligned_le16(dev_id, &rp->index);
927 put_unaligned_le16(count, &rp->conn_count);
928
929 read_lock(&hci_dev_list_lock);
930
931 i = 0;
932 list_for_each(p, &hdev->conn_hash.list) {
933 struct hci_conn *c = list_entry(p, struct hci_conn, list);
934
935 bacpy(&rp->conn[i++], &c->dst);
936 }
937
938 read_unlock(&hci_dev_list_lock);
939
Johan Hedberga38528f2011-01-22 06:46:43 +0200940 err = cmd_complete(sk, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200941
942unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200943 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200944 hci_dev_unlock_bh(hdev);
945 hci_dev_put(hdev);
946 return err;
947}
948
Johan Hedberg980e1a52011-01-22 06:10:07 +0200949static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
950{
951 struct hci_dev *hdev;
952 struct mgmt_cp_pin_code_reply *cp;
953 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300954 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200955 u16 dev_id;
956 int err;
957
958 BT_DBG("");
959
960 cp = (void *) data;
961 dev_id = get_unaligned_le16(&cp->index);
962
963 hdev = hci_dev_get(dev_id);
964 if (!hdev)
965 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
966
967 hci_dev_lock_bh(hdev);
968
969 if (!test_bit(HCI_UP, &hdev->flags)) {
970 err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
971 goto failed;
972 }
973
Johan Hedberg366a0332011-02-19 12:05:55 -0300974 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
975 if (!cmd) {
976 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200977 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300978 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200979
980 bacpy(&reply.bdaddr, &cp->bdaddr);
981 reply.pin_len = cp->pin_len;
982 memcpy(reply.pin_code, cp->pin_code, 16);
983
984 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
985 if (err < 0)
986 mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
987
988failed:
989 hci_dev_unlock_bh(hdev);
990 hci_dev_put(hdev);
991
992 return err;
993}
994
995static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
996{
997 struct hci_dev *hdev;
998 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -0300999 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001000 u16 dev_id;
1001 int err;
1002
1003 BT_DBG("");
1004
1005 cp = (void *) data;
1006 dev_id = get_unaligned_le16(&cp->index);
1007
1008 hdev = hci_dev_get(dev_id);
1009 if (!hdev)
1010 return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
1011
1012 hci_dev_lock_bh(hdev);
1013
1014 if (!test_bit(HCI_UP, &hdev->flags)) {
1015 err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
1016 goto failed;
1017 }
1018
Johan Hedberg366a0332011-02-19 12:05:55 -03001019 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001020 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001021 if (!cmd) {
1022 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001023 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001024 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001025
1026 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1027 &cp->bdaddr);
1028 if (err < 0)
1029 mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
1030
1031failed:
1032 hci_dev_unlock_bh(hdev);
1033 hci_dev_put(hdev);
1034
1035 return err;
1036}
1037
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001038static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
1039{
1040 struct hci_dev *hdev;
1041 struct mgmt_cp_set_io_capability *cp;
1042 u16 dev_id;
1043
1044 BT_DBG("");
1045
1046 cp = (void *) data;
1047 dev_id = get_unaligned_le16(&cp->index);
1048
1049 hdev = hci_dev_get(dev_id);
1050 if (!hdev)
1051 return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
1052
1053 hci_dev_lock_bh(hdev);
1054
1055 hdev->io_capability = cp->io_capability;
1056
1057 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1058 hdev->io_capability);
1059
1060 hci_dev_unlock_bh(hdev);
1061 hci_dev_put(hdev);
1062
1063 return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY,
1064 &dev_id, sizeof(dev_id));
1065}
1066
Johan Hedberge9a416b2011-02-19 12:05:56 -03001067static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1068{
1069 struct hci_dev *hdev = conn->hdev;
1070 struct list_head *p;
1071
1072 list_for_each(p, &cmd_list) {
1073 struct pending_cmd *cmd;
1074
1075 cmd = list_entry(p, struct pending_cmd, list);
1076
1077 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1078 continue;
1079
1080 if (cmd->index != hdev->id)
1081 continue;
1082
1083 if (cmd->user_data != conn)
1084 continue;
1085
1086 return cmd;
1087 }
1088
1089 return NULL;
1090}
1091
1092static void pairing_complete(struct pending_cmd *cmd, u8 status)
1093{
1094 struct mgmt_rp_pair_device rp;
1095 struct hci_conn *conn = cmd->user_data;
1096
1097 rp.index = cmd->index;
1098 bacpy(&rp.bdaddr, &conn->dst);
1099 rp.status = status;
1100
1101 cmd_complete(cmd->sk, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
1102
1103 /* So we don't get further callbacks for this connection */
1104 conn->connect_cfm_cb = NULL;
1105 conn->security_cfm_cb = NULL;
1106 conn->disconn_cfm_cb = NULL;
1107
1108 hci_conn_put(conn);
1109
1110 list_del(&cmd->list);
1111 mgmt_pending_free(cmd);
1112}
1113
1114static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1115{
1116 struct pending_cmd *cmd;
1117
1118 BT_DBG("status %u", status);
1119
1120 cmd = find_pairing(conn);
1121 if (!cmd) {
1122 BT_DBG("Unable to find a pending command");
1123 return;
1124 }
1125
1126 pairing_complete(cmd, status);
1127}
1128
1129static int pair_device(struct sock *sk, unsigned char *data, u16 len)
1130{
1131 struct hci_dev *hdev;
1132 struct mgmt_cp_pair_device *cp;
1133 struct pending_cmd *cmd;
1134 u8 sec_level, auth_type;
1135 struct hci_conn *conn;
1136 u16 dev_id;
1137 int err;
1138
1139 BT_DBG("");
1140
1141 cp = (void *) data;
1142 dev_id = get_unaligned_le16(&cp->index);
1143
1144 hdev = hci_dev_get(dev_id);
1145 if (!hdev)
1146 return cmd_status(sk, MGMT_OP_PAIR_DEVICE, ENODEV);
1147
1148 hci_dev_lock_bh(hdev);
1149
1150 if (cp->io_cap == 0x03) {
1151 sec_level = BT_SECURITY_MEDIUM;
1152 auth_type = HCI_AT_DEDICATED_BONDING;
1153 } else {
1154 sec_level = BT_SECURITY_HIGH;
1155 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1156 }
1157
1158 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
1159 if (!conn) {
1160 err = -ENOMEM;
1161 goto unlock;
1162 }
1163
1164 if (conn->connect_cfm_cb) {
1165 hci_conn_put(conn);
1166 err = cmd_status(sk, MGMT_OP_PAIR_DEVICE, EBUSY);
1167 goto unlock;
1168 }
1169
1170 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, dev_id, data, len);
1171 if (!cmd) {
1172 err = -ENOMEM;
1173 hci_conn_put(conn);
1174 goto unlock;
1175 }
1176
1177 conn->connect_cfm_cb = pairing_complete_cb;
1178 conn->security_cfm_cb = pairing_complete_cb;
1179 conn->disconn_cfm_cb = pairing_complete_cb;
1180 conn->io_capability = cp->io_cap;
1181 cmd->user_data = conn;
1182
1183 if (conn->state == BT_CONNECTED &&
1184 hci_conn_security(conn, sec_level, auth_type))
1185 pairing_complete(cmd, 0);
1186
1187 err = 0;
1188
1189unlock:
1190 hci_dev_unlock_bh(hdev);
1191 hci_dev_put(hdev);
1192
1193 return err;
1194}
1195
Johan Hedberg03811012010-12-08 00:21:06 +02001196int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1197{
1198 unsigned char *buf;
1199 struct mgmt_hdr *hdr;
1200 u16 opcode, len;
1201 int err;
1202
1203 BT_DBG("got %zu bytes", msglen);
1204
1205 if (msglen < sizeof(*hdr))
1206 return -EINVAL;
1207
1208 buf = kmalloc(msglen, GFP_ATOMIC);
1209 if (!buf)
1210 return -ENOMEM;
1211
1212 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1213 err = -EFAULT;
1214 goto done;
1215 }
1216
1217 hdr = (struct mgmt_hdr *) buf;
1218 opcode = get_unaligned_le16(&hdr->opcode);
1219 len = get_unaligned_le16(&hdr->len);
1220
1221 if (len != msglen - sizeof(*hdr)) {
1222 err = -EINVAL;
1223 goto done;
1224 }
1225
1226 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001227 case MGMT_OP_READ_VERSION:
1228 err = read_version(sk);
1229 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001230 case MGMT_OP_READ_INDEX_LIST:
1231 err = read_index_list(sk);
1232 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001233 case MGMT_OP_READ_INFO:
1234 err = read_controller_info(sk, buf + sizeof(*hdr), len);
1235 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001236 case MGMT_OP_SET_POWERED:
1237 err = set_powered(sk, buf + sizeof(*hdr), len);
1238 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001239 case MGMT_OP_SET_DISCOVERABLE:
1240 err = set_discoverable(sk, buf + sizeof(*hdr), len);
1241 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001242 case MGMT_OP_SET_CONNECTABLE:
1243 err = set_connectable(sk, buf + sizeof(*hdr), len);
1244 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001245 case MGMT_OP_SET_PAIRABLE:
1246 err = set_pairable(sk, buf + sizeof(*hdr), len);
1247 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248 case MGMT_OP_ADD_UUID:
1249 err = add_uuid(sk, buf + sizeof(*hdr), len);
1250 break;
1251 case MGMT_OP_REMOVE_UUID:
1252 err = remove_uuid(sk, buf + sizeof(*hdr), len);
1253 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001254 case MGMT_OP_SET_DEV_CLASS:
1255 err = set_dev_class(sk, buf + sizeof(*hdr), len);
1256 break;
1257 case MGMT_OP_SET_SERVICE_CACHE:
1258 err = set_service_cache(sk, buf + sizeof(*hdr), len);
1259 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001260 case MGMT_OP_LOAD_KEYS:
1261 err = load_keys(sk, buf + sizeof(*hdr), len);
1262 break;
1263 case MGMT_OP_REMOVE_KEY:
1264 err = remove_key(sk, buf + sizeof(*hdr), len);
1265 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001266 case MGMT_OP_DISCONNECT:
1267 err = disconnect(sk, buf + sizeof(*hdr), len);
1268 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269 case MGMT_OP_GET_CONNECTIONS:
1270 err = get_connections(sk, buf + sizeof(*hdr), len);
1271 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001272 case MGMT_OP_PIN_CODE_REPLY:
1273 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1274 break;
1275 case MGMT_OP_PIN_CODE_NEG_REPLY:
1276 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1277 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001278 case MGMT_OP_SET_IO_CAPABILITY:
1279 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1280 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001281 case MGMT_OP_PAIR_DEVICE:
1282 err = pair_device(sk, buf + sizeof(*hdr), len);
1283 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001284 default:
1285 BT_DBG("Unknown op %u", opcode);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001286 err = cmd_status(sk, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001287 break;
1288 }
1289
Johan Hedberge41d8b42010-12-13 21:07:03 +02001290 if (err < 0)
1291 goto done;
1292
Johan Hedberg03811012010-12-08 00:21:06 +02001293 err = msglen;
1294
1295done:
1296 kfree(buf);
1297 return err;
1298}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001299
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001300int mgmt_index_added(u16 index)
1301{
1302 struct mgmt_ev_index_added ev;
1303
1304 put_unaligned_le16(index, &ev.index);
1305
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001306 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001307}
1308
1309int mgmt_index_removed(u16 index)
1310{
1311 struct mgmt_ev_index_added ev;
1312
1313 put_unaligned_le16(index, &ev.index);
1314
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001315 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
1316}
1317
Johan Hedberg73f22f62010-12-29 16:00:25 +02001318struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001319 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001320 struct sock *sk;
1321};
1322
Johan Hedberg72a734e2010-12-30 00:38:22 +02001323static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001324{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001325 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001326 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001327
Johan Hedberg72a734e2010-12-30 00:38:22 +02001328 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001329 return;
1330
Johan Hedberg053f0212011-01-26 13:07:10 +02001331 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001332
1333 list_del(&cmd->list);
1334
1335 if (match->sk == NULL) {
1336 match->sk = cmd->sk;
1337 sock_hold(match->sk);
1338 }
1339
1340 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001341}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001342
1343int mgmt_powered(u16 index, u8 powered)
1344{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001345 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001346 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001347 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001348
Johan Hedberg72a734e2010-12-30 00:38:22 +02001349 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001350
Johan Hedberg72a734e2010-12-30 00:38:22 +02001351 put_unaligned_le16(index, &ev.index);
1352 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001353
1354 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
1355
1356 if (match.sk)
1357 sock_put(match.sk);
1358
1359 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001360}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001361
Johan Hedberg73f22f62010-12-29 16:00:25 +02001362int mgmt_discoverable(u16 index, u8 discoverable)
1363{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001364 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001365 struct cmd_lookup match = { discoverable, NULL };
1366 int ret;
1367
Johan Hedberg73f22f62010-12-29 16:00:25 +02001368 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001369 mode_rsp, &match);
1370
1371 put_unaligned_le16(index, &ev.index);
1372 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001373
1374 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
1375
1376 if (match.sk)
1377 sock_put(match.sk);
1378
1379 return ret;
1380}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001381
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001382int mgmt_connectable(u16 index, u8 connectable)
1383{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001384 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001385 struct cmd_lookup match = { connectable, NULL };
1386 int ret;
1387
Johan Hedberg72a734e2010-12-30 00:38:22 +02001388 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001389
Johan Hedberg72a734e2010-12-30 00:38:22 +02001390 put_unaligned_le16(index, &ev.index);
1391 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001392
1393 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
1394
1395 if (match.sk)
1396 sock_put(match.sk);
1397
1398 return ret;
1399}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001400
1401int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1402{
1403 struct mgmt_ev_new_key ev;
1404
1405 memset(&ev, 0, sizeof(ev));
1406
1407 put_unaligned_le16(index, &ev.index);
1408
1409 bacpy(&ev.key.bdaddr, &key->bdaddr);
1410 ev.key.type = key->type;
1411 memcpy(ev.key.val, key->val, 16);
1412 ev.key.pin_len = key->pin_len;
1413 ev.old_key_type = old_key_type;
1414
1415 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1416}
Johan Hedbergf7520542011-01-20 12:34:39 +02001417
1418int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1419{
1420 struct mgmt_ev_connected ev;
1421
1422 put_unaligned_le16(index, &ev.index);
1423 bacpy(&ev.bdaddr, bdaddr);
1424
1425 return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
1426}
1427
Johan Hedberg8962ee72011-01-20 12:40:27 +02001428static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1429{
1430 struct mgmt_cp_disconnect *cp = cmd->cmd;
1431 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001432 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001433
Johan Hedberga38528f2011-01-22 06:46:43 +02001434 put_unaligned_le16(cmd->index, &rp.index);
1435 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001436
Johan Hedberga38528f2011-01-22 06:46:43 +02001437 cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001438
1439 *sk = cmd->sk;
1440 sock_hold(*sk);
1441
1442 list_del(&cmd->list);
1443 mgmt_pending_free(cmd);
1444}
1445
Johan Hedbergf7520542011-01-20 12:34:39 +02001446int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1447{
1448 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001449 struct sock *sk = NULL;
1450 int err;
1451
1452 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001453
1454 put_unaligned_le16(index, &ev.index);
1455 bacpy(&ev.bdaddr, bdaddr);
1456
Johan Hedberg8962ee72011-01-20 12:40:27 +02001457 err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
1458
1459 if (sk)
1460 sock_put(sk);
1461
1462 return err;
1463}
1464
1465int mgmt_disconnect_failed(u16 index)
1466{
1467 struct pending_cmd *cmd;
1468 int err;
1469
1470 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1471 if (!cmd)
1472 return -ENOENT;
1473
1474 err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
1475
1476 list_del(&cmd->list);
1477 mgmt_pending_free(cmd);
1478
1479 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001480}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001481
1482int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1483{
1484 struct mgmt_ev_connect_failed ev;
1485
1486 put_unaligned_le16(index, &ev.index);
1487 bacpy(&ev.bdaddr, bdaddr);
1488 ev.status = status;
1489
1490 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1491}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001492
1493int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1494{
1495 struct mgmt_ev_pin_code_request ev;
1496
1497 put_unaligned_le16(index, &ev.index);
1498 bacpy(&ev.bdaddr, bdaddr);
1499
1500 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1501}
1502
1503int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1504{
1505 struct pending_cmd *cmd;
1506 int err;
1507
1508 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1509 if (!cmd)
1510 return -ENOENT;
1511
1512 if (status != 0)
1513 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
1514 else
1515 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
1516 bdaddr, sizeof(*bdaddr));
1517
1518 list_del(&cmd->list);
1519 mgmt_pending_free(cmd);
1520
1521 return err;
1522}
1523
1524int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1525{
1526 struct pending_cmd *cmd;
1527 int err;
1528
1529 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1530 if (!cmd)
1531 return -ENOENT;
1532
1533 if (status != 0)
1534 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
1535 else
1536 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1537 bdaddr, sizeof(*bdaddr));
1538
1539 list_del(&cmd->list);
1540 mgmt_pending_free(cmd);
1541
1542 return err;
1543}