blob: 0d3d613baac2b5335e8ba09f7b53ddd790d127d2 [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)
Johan Hedberg59a24b52011-02-19 12:05:58 -0300965 return cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200966
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 Hedberga5c29682011-02-19 12:05:57 -03001196static int user_confirm_reply(struct sock *sk, unsigned char *data, u16 len,
1197 int success)
1198{
1199 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1200 u16 dev_id, mgmt_op, hci_op;
1201 struct pending_cmd *cmd;
1202 struct hci_dev *hdev;
1203 int err;
1204
1205 BT_DBG("");
1206
1207 dev_id = get_unaligned_le16(&cp->index);
1208
1209 if (success) {
1210 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1211 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1212 } else {
1213 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1214 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1215 }
1216
1217 hdev = hci_dev_get(dev_id);
1218 if (!hdev)
1219 return cmd_status(sk, mgmt_op, ENODEV);
1220
1221 if (!test_bit(HCI_UP, &hdev->flags)) {
1222 err = cmd_status(sk, mgmt_op, ENETDOWN);
1223 goto failed;
1224 }
1225
1226 cmd = mgmt_pending_add(sk, mgmt_op, dev_id, data, len);
1227 if (!cmd) {
1228 err = -ENOMEM;
1229 goto failed;
1230 }
1231
1232 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1233 if (err < 0) {
1234 list_del(&cmd->list);
1235 mgmt_pending_free(cmd);
1236 }
1237
1238failed:
1239 hci_dev_unlock_bh(hdev);
1240 hci_dev_put(hdev);
1241
1242 return err;
1243}
1244
Johan Hedberg03811012010-12-08 00:21:06 +02001245int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1246{
1247 unsigned char *buf;
1248 struct mgmt_hdr *hdr;
1249 u16 opcode, len;
1250 int err;
1251
1252 BT_DBG("got %zu bytes", msglen);
1253
1254 if (msglen < sizeof(*hdr))
1255 return -EINVAL;
1256
1257 buf = kmalloc(msglen, GFP_ATOMIC);
1258 if (!buf)
1259 return -ENOMEM;
1260
1261 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1262 err = -EFAULT;
1263 goto done;
1264 }
1265
1266 hdr = (struct mgmt_hdr *) buf;
1267 opcode = get_unaligned_le16(&hdr->opcode);
1268 len = get_unaligned_le16(&hdr->len);
1269
1270 if (len != msglen - sizeof(*hdr)) {
1271 err = -EINVAL;
1272 goto done;
1273 }
1274
1275 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001276 case MGMT_OP_READ_VERSION:
1277 err = read_version(sk);
1278 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001279 case MGMT_OP_READ_INDEX_LIST:
1280 err = read_index_list(sk);
1281 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001282 case MGMT_OP_READ_INFO:
1283 err = read_controller_info(sk, buf + sizeof(*hdr), len);
1284 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001285 case MGMT_OP_SET_POWERED:
1286 err = set_powered(sk, buf + sizeof(*hdr), len);
1287 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001288 case MGMT_OP_SET_DISCOVERABLE:
1289 err = set_discoverable(sk, buf + sizeof(*hdr), len);
1290 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001291 case MGMT_OP_SET_CONNECTABLE:
1292 err = set_connectable(sk, buf + sizeof(*hdr), len);
1293 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001294 case MGMT_OP_SET_PAIRABLE:
1295 err = set_pairable(sk, buf + sizeof(*hdr), len);
1296 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001297 case MGMT_OP_ADD_UUID:
1298 err = add_uuid(sk, buf + sizeof(*hdr), len);
1299 break;
1300 case MGMT_OP_REMOVE_UUID:
1301 err = remove_uuid(sk, buf + sizeof(*hdr), len);
1302 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001303 case MGMT_OP_SET_DEV_CLASS:
1304 err = set_dev_class(sk, buf + sizeof(*hdr), len);
1305 break;
1306 case MGMT_OP_SET_SERVICE_CACHE:
1307 err = set_service_cache(sk, buf + sizeof(*hdr), len);
1308 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001309 case MGMT_OP_LOAD_KEYS:
1310 err = load_keys(sk, buf + sizeof(*hdr), len);
1311 break;
1312 case MGMT_OP_REMOVE_KEY:
1313 err = remove_key(sk, buf + sizeof(*hdr), len);
1314 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001315 case MGMT_OP_DISCONNECT:
1316 err = disconnect(sk, buf + sizeof(*hdr), len);
1317 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001318 case MGMT_OP_GET_CONNECTIONS:
1319 err = get_connections(sk, buf + sizeof(*hdr), len);
1320 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001321 case MGMT_OP_PIN_CODE_REPLY:
1322 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1323 break;
1324 case MGMT_OP_PIN_CODE_NEG_REPLY:
1325 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1326 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001327 case MGMT_OP_SET_IO_CAPABILITY:
1328 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1329 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001330 case MGMT_OP_PAIR_DEVICE:
1331 err = pair_device(sk, buf + sizeof(*hdr), len);
1332 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001333 case MGMT_OP_USER_CONFIRM_REPLY:
1334 err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 1);
1335 break;
1336 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
1337 err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 0);
1338 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001339 default:
1340 BT_DBG("Unknown op %u", opcode);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001341 err = cmd_status(sk, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001342 break;
1343 }
1344
Johan Hedberge41d8b42010-12-13 21:07:03 +02001345 if (err < 0)
1346 goto done;
1347
Johan Hedberg03811012010-12-08 00:21:06 +02001348 err = msglen;
1349
1350done:
1351 kfree(buf);
1352 return err;
1353}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001354
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001355int mgmt_index_added(u16 index)
1356{
1357 struct mgmt_ev_index_added ev;
1358
1359 put_unaligned_le16(index, &ev.index);
1360
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001361 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001362}
1363
1364int mgmt_index_removed(u16 index)
1365{
1366 struct mgmt_ev_index_added ev;
1367
1368 put_unaligned_le16(index, &ev.index);
1369
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001370 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
1371}
1372
Johan Hedberg73f22f62010-12-29 16:00:25 +02001373struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001374 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001375 struct sock *sk;
1376};
1377
Johan Hedberg72a734e2010-12-30 00:38:22 +02001378static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001379{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001380 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001381 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001382
Johan Hedberg72a734e2010-12-30 00:38:22 +02001383 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001384 return;
1385
Johan Hedberg053f0212011-01-26 13:07:10 +02001386 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001387
1388 list_del(&cmd->list);
1389
1390 if (match->sk == NULL) {
1391 match->sk = cmd->sk;
1392 sock_hold(match->sk);
1393 }
1394
1395 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001396}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001397
1398int mgmt_powered(u16 index, u8 powered)
1399{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001400 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001401 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001402 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001403
Johan Hedberg72a734e2010-12-30 00:38:22 +02001404 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001405
Johan Hedberg72a734e2010-12-30 00:38:22 +02001406 put_unaligned_le16(index, &ev.index);
1407 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408
1409 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
1410
1411 if (match.sk)
1412 sock_put(match.sk);
1413
1414 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001415}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001416
Johan Hedberg73f22f62010-12-29 16:00:25 +02001417int mgmt_discoverable(u16 index, u8 discoverable)
1418{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001419 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001420 struct cmd_lookup match = { discoverable, NULL };
1421 int ret;
1422
Johan Hedberg73f22f62010-12-29 16:00:25 +02001423 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001424 mode_rsp, &match);
1425
1426 put_unaligned_le16(index, &ev.index);
1427 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001428
1429 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
1430
1431 if (match.sk)
1432 sock_put(match.sk);
1433
1434 return ret;
1435}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001436
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001437int mgmt_connectable(u16 index, u8 connectable)
1438{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001439 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001440 struct cmd_lookup match = { connectable, NULL };
1441 int ret;
1442
Johan Hedberg72a734e2010-12-30 00:38:22 +02001443 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001444
Johan Hedberg72a734e2010-12-30 00:38:22 +02001445 put_unaligned_le16(index, &ev.index);
1446 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001447
1448 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
1449
1450 if (match.sk)
1451 sock_put(match.sk);
1452
1453 return ret;
1454}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001455
1456int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1457{
1458 struct mgmt_ev_new_key ev;
1459
1460 memset(&ev, 0, sizeof(ev));
1461
1462 put_unaligned_le16(index, &ev.index);
1463
1464 bacpy(&ev.key.bdaddr, &key->bdaddr);
1465 ev.key.type = key->type;
1466 memcpy(ev.key.val, key->val, 16);
1467 ev.key.pin_len = key->pin_len;
1468 ev.old_key_type = old_key_type;
1469
1470 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1471}
Johan Hedbergf7520542011-01-20 12:34:39 +02001472
1473int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1474{
1475 struct mgmt_ev_connected ev;
1476
1477 put_unaligned_le16(index, &ev.index);
1478 bacpy(&ev.bdaddr, bdaddr);
1479
1480 return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
1481}
1482
Johan Hedberg8962ee72011-01-20 12:40:27 +02001483static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1484{
1485 struct mgmt_cp_disconnect *cp = cmd->cmd;
1486 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001487 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488
Johan Hedberga38528f2011-01-22 06:46:43 +02001489 put_unaligned_le16(cmd->index, &rp.index);
1490 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491
Johan Hedberga38528f2011-01-22 06:46:43 +02001492 cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001493
1494 *sk = cmd->sk;
1495 sock_hold(*sk);
1496
1497 list_del(&cmd->list);
1498 mgmt_pending_free(cmd);
1499}
1500
Johan Hedbergf7520542011-01-20 12:34:39 +02001501int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1502{
1503 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001504 struct sock *sk = NULL;
1505 int err;
1506
1507 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001508
1509 put_unaligned_le16(index, &ev.index);
1510 bacpy(&ev.bdaddr, bdaddr);
1511
Johan Hedberg8962ee72011-01-20 12:40:27 +02001512 err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
1513
1514 if (sk)
1515 sock_put(sk);
1516
1517 return err;
1518}
1519
1520int mgmt_disconnect_failed(u16 index)
1521{
1522 struct pending_cmd *cmd;
1523 int err;
1524
1525 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1526 if (!cmd)
1527 return -ENOENT;
1528
1529 err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
1530
1531 list_del(&cmd->list);
1532 mgmt_pending_free(cmd);
1533
1534 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001535}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001536
1537int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1538{
1539 struct mgmt_ev_connect_failed ev;
1540
1541 put_unaligned_le16(index, &ev.index);
1542 bacpy(&ev.bdaddr, bdaddr);
1543 ev.status = status;
1544
1545 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1546}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001547
1548int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1549{
1550 struct mgmt_ev_pin_code_request ev;
1551
1552 put_unaligned_le16(index, &ev.index);
1553 bacpy(&ev.bdaddr, bdaddr);
1554
1555 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1556}
1557
1558int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1559{
1560 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001561 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001562 int err;
1563
1564 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1565 if (!cmd)
1566 return -ENOENT;
1567
Johan Hedbergac56fb12011-02-19 12:05:59 -03001568 put_unaligned_le16(index, &rp.index);
1569 bacpy(&rp.bdaddr, bdaddr);
1570 rp.status = status;
1571
1572 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY, &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001573
1574 list_del(&cmd->list);
1575 mgmt_pending_free(cmd);
1576
1577 return err;
1578}
1579
1580int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1581{
1582 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001583 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001584 int err;
1585
1586 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1587 if (!cmd)
1588 return -ENOENT;
1589
Johan Hedbergac56fb12011-02-19 12:05:59 -03001590 put_unaligned_le16(index, &rp.index);
1591 bacpy(&rp.bdaddr, bdaddr);
1592 rp.status = status;
1593
1594 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1595 &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001596
1597 list_del(&cmd->list);
1598 mgmt_pending_free(cmd);
1599
1600 return err;
1601}
Johan Hedberga5c29682011-02-19 12:05:57 -03001602
1603int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1604{
1605 struct mgmt_ev_user_confirm_request ev;
1606
1607 BT_DBG("hci%u", index);
1608
1609 put_unaligned_le16(index, &ev.index);
1610 bacpy(&ev.bdaddr, bdaddr);
1611 put_unaligned_le32(value, &ev.value);
1612
1613 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, &ev, sizeof(ev), NULL);
1614}
1615
1616static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1617 u8 opcode)
1618{
1619 struct pending_cmd *cmd;
1620 struct mgmt_rp_user_confirm_reply rp;
1621 int err;
1622
1623 cmd = mgmt_pending_find(opcode, index);
1624 if (!cmd)
1625 return -ENOENT;
1626
1627 put_unaligned_le16(index, &rp.index);
1628 bacpy(&rp.bdaddr, bdaddr);
1629 rp.status = status;
1630 err = cmd_complete(cmd->sk, opcode, &rp, sizeof(rp));
1631
1632 list_del(&cmd->list);
1633 mgmt_pending_free(cmd);
1634
1635 return err;
1636}
1637
1638int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1639{
1640 return confirm_reply_complete(index, bdaddr, status,
1641 MGMT_OP_USER_CONFIRM_REPLY);
1642}
1643
1644int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1645 u8 status)
1646{
1647 return confirm_reply_complete(index, bdaddr, status,
1648 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1649}