Bluetooth: Add read_local_oob_data management command
[deliverable/linux.git] / net / bluetooth / mgmt.c
CommitLineData
0381101f
JH
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
72359753 25#include <linux/uaccess.h>
0381101f
JH
26#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
02d98129
JH
32#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
eec8d2bc
JH
35struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
c68fb7ff 39 void *param;
eec8d2bc 40 struct sock *sk;
e9a416b5 41 void *user_data;
eec8d2bc
JH
42};
43
44LIST_HEAD(cmd_list);
45
4e51eae9 46static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
f7b64e69
JH
47{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
34eb525c 52 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
f7b64e69
JH
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);
4e51eae9 61 hdr->index = cpu_to_le16(index);
f7b64e69
JH
62 hdr->len = cpu_to_le16(sizeof(*ev));
63
64 ev = (void *) skb_put(skb, sizeof(*ev));
65 ev->status = status;
66 put_unaligned_le16(cmd, &ev->opcode);
67
68 if (sock_queue_rcv_skb(sk, skb) < 0)
69 kfree_skb(skb);
70
71 return 0;
72}
73
4e51eae9
SJ
74static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
75 size_t rp_len)
02d98129
JH
76{
77 struct sk_buff *skb;
78 struct mgmt_hdr *hdr;
79 struct mgmt_ev_cmd_complete *ev;
02d98129
JH
80
81 BT_DBG("sock %p", sk);
82
a38528f1 83 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
02d98129
JH
84 if (!skb)
85 return -ENOMEM;
86
87 hdr = (void *) skb_put(skb, sizeof(*hdr));
02d98129 88
a38528f1 89 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
4e51eae9 90 hdr->index = cpu_to_le16(index);
a38528f1 91 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
02d98129 92
a38528f1
JH
93 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
94 put_unaligned_le16(cmd, &ev->opcode);
8020c16a
SJ
95
96 if (rp)
97 memcpy(ev->data, rp, rp_len);
02d98129
JH
98
99 if (sock_queue_rcv_skb(sk, skb) < 0)
100 kfree_skb(skb);
101
102 return 0;
103}
104
a38528f1
JH
105static int read_version(struct sock *sk)
106{
107 struct mgmt_rp_read_version rp;
108
109 BT_DBG("sock %p", sk);
110
111 rp.version = MGMT_VERSION;
112 put_unaligned_le16(MGMT_REVISION, &rp.revision);
113
4e51eae9
SJ
114 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
115 sizeof(rp));
a38528f1
JH
116}
117
faba42eb
JH
118static int read_index_list(struct sock *sk)
119{
faba42eb
JH
120 struct mgmt_rp_read_index_list *rp;
121 struct list_head *p;
a38528f1 122 size_t rp_len;
faba42eb 123 u16 count;
a38528f1 124 int i, err;
faba42eb
JH
125
126 BT_DBG("sock %p", sk);
127
128 read_lock(&hci_dev_list_lock);
129
130 count = 0;
131 list_for_each(p, &hci_dev_list) {
132 count++;
133 }
134
a38528f1
JH
135 rp_len = sizeof(*rp) + (2 * count);
136 rp = kmalloc(rp_len, GFP_ATOMIC);
137 if (!rp) {
b2c60d42 138 read_unlock(&hci_dev_list_lock);
faba42eb 139 return -ENOMEM;
b2c60d42 140 }
faba42eb 141
faba42eb
JH
142 put_unaligned_le16(count, &rp->num_controllers);
143
144 i = 0;
145 list_for_each(p, &hci_dev_list) {
146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
ab81cbf9
JH
147
148 hci_del_off_timer(d);
149
ebc99feb
JH
150 set_bit(HCI_MGMT, &d->flags);
151
ab81cbf9
JH
152 if (test_bit(HCI_SETUP, &d->flags))
153 continue;
154
faba42eb
JH
155 put_unaligned_le16(d->id, &rp->index[i++]);
156 BT_DBG("Added hci%u", d->id);
157 }
158
159 read_unlock(&hci_dev_list_lock);
160
4e51eae9
SJ
161 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
162 rp_len);
faba42eb 163
a38528f1
JH
164 kfree(rp);
165
166 return err;
faba42eb
JH
167}
168
4e51eae9 169static int read_controller_info(struct sock *sk, u16 index)
0381101f 170{
a38528f1 171 struct mgmt_rp_read_info rp;
f7b64e69 172 struct hci_dev *hdev;
0381101f 173
4e51eae9 174 BT_DBG("sock %p hci%u", sk, index);
f7b64e69 175
4e51eae9 176 hdev = hci_dev_get(index);
a38528f1 177 if (!hdev)
4e51eae9 178 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
f7b64e69 179
ab81cbf9
JH
180 hci_del_off_timer(hdev);
181
f7b64e69
JH
182 hci_dev_lock_bh(hdev);
183
ebc99feb
JH
184 set_bit(HCI_MGMT, &hdev->flags);
185
dc4fe30b
JH
186 memset(&rp, 0, sizeof(rp));
187
a38528f1 188 rp.type = hdev->dev_type;
f7b64e69 189
a38528f1
JH
190 rp.powered = test_bit(HCI_UP, &hdev->flags);
191 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
192 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
193 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
f7b64e69
JH
194
195 if (test_bit(HCI_AUTH, &hdev->flags))
a38528f1 196 rp.sec_mode = 3;
f7b64e69 197 else if (hdev->ssp_mode > 0)
a38528f1 198 rp.sec_mode = 4;
f7b64e69 199 else
a38528f1 200 rp.sec_mode = 2;
f7b64e69 201
a38528f1
JH
202 bacpy(&rp.bdaddr, &hdev->bdaddr);
203 memcpy(rp.features, hdev->features, 8);
204 memcpy(rp.dev_class, hdev->dev_class, 3);
205 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
206 rp.hci_ver = hdev->hci_ver;
207 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
f7b64e69 208
dc4fe30b
JH
209 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
210
f7b64e69
JH
211 hci_dev_unlock_bh(hdev);
212 hci_dev_put(hdev);
0381101f 213
4e51eae9 214 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
0381101f
JH
215}
216
eec8d2bc
JH
217static void mgmt_pending_free(struct pending_cmd *cmd)
218{
219 sock_put(cmd->sk);
c68fb7ff 220 kfree(cmd->param);
eec8d2bc
JH
221 kfree(cmd);
222}
223
366a0336
JH
224static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
225 u16 index, void *data, u16 len)
eec8d2bc
JH
226{
227 struct pending_cmd *cmd;
228
229 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
230 if (!cmd)
366a0336 231 return NULL;
eec8d2bc
JH
232
233 cmd->opcode = opcode;
234 cmd->index = index;
235
c68fb7ff
SJ
236 cmd->param = kmalloc(len, GFP_ATOMIC);
237 if (!cmd->param) {
eec8d2bc 238 kfree(cmd);
366a0336 239 return NULL;
eec8d2bc
JH
240 }
241
8fce6357
SJ
242 if (data)
243 memcpy(cmd->param, data, len);
eec8d2bc
JH
244
245 cmd->sk = sk;
246 sock_hold(sk);
247
248 list_add(&cmd->list, &cmd_list);
249
366a0336 250 return cmd;
eec8d2bc
JH
251}
252
253static void mgmt_pending_foreach(u16 opcode, int index,
254 void (*cb)(struct pending_cmd *cmd, void *data),
255 void *data)
256{
257 struct list_head *p, *n;
258
259 list_for_each_safe(p, n, &cmd_list) {
260 struct pending_cmd *cmd;
261
262 cmd = list_entry(p, struct pending_cmd, list);
263
264 if (cmd->opcode != opcode)
265 continue;
266
267 if (index >= 0 && cmd->index != index)
268 continue;
269
270 cb(cmd, data);
271 }
272}
273
274static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
275{
276 struct list_head *p;
277
278 list_for_each(p, &cmd_list) {
279 struct pending_cmd *cmd;
280
281 cmd = list_entry(p, struct pending_cmd, list);
282
283 if (cmd->opcode != opcode)
284 continue;
285
286 if (index >= 0 && cmd->index != index)
287 continue;
288
289 return cmd;
290 }
291
292 return NULL;
293}
294
a664b5bc 295static void mgmt_pending_remove(struct pending_cmd *cmd)
73f22f62 296{
73f22f62
JH
297 list_del(&cmd->list);
298 mgmt_pending_free(cmd);
299}
300
4e51eae9 301static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
eec8d2bc 302{
72a734ec 303 struct mgmt_mode *cp;
eec8d2bc 304 struct hci_dev *hdev;
366a0336 305 struct pending_cmd *cmd;
366a0336 306 int err, up;
eec8d2bc
JH
307
308 cp = (void *) data;
eec8d2bc 309
4e51eae9 310 BT_DBG("request for hci%u", index);
eec8d2bc 311
bdce7baf
SJ
312 if (len != sizeof(*cp))
313 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
314
4e51eae9 315 hdev = hci_dev_get(index);
eec8d2bc 316 if (!hdev)
4e51eae9 317 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
eec8d2bc
JH
318
319 hci_dev_lock_bh(hdev);
320
321 up = test_bit(HCI_UP, &hdev->flags);
72a734ec 322 if ((cp->val && up) || (!cp->val && !up)) {
4e51eae9 323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
eec8d2bc
JH
324 goto failed;
325 }
326
4e51eae9
SJ
327 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
328 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
eec8d2bc
JH
329 goto failed;
330 }
331
4e51eae9 332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
366a0336
JH
333 if (!cmd) {
334 err = -ENOMEM;
eec8d2bc 335 goto failed;
366a0336 336 }
eec8d2bc 337
72a734ec 338 if (cp->val)
eec8d2bc
JH
339 queue_work(hdev->workqueue, &hdev->power_on);
340 else
341 queue_work(hdev->workqueue, &hdev->power_off);
342
366a0336 343 err = 0;
eec8d2bc
JH
344
345failed:
346 hci_dev_unlock_bh(hdev);
347 hci_dev_put(hdev);
366a0336 348 return err;
eec8d2bc
JH
349}
350
4e51eae9
SJ
351static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
352 u16 len)
73f22f62 353{
72a734ec 354 struct mgmt_mode *cp;
73f22f62 355 struct hci_dev *hdev;
366a0336 356 struct pending_cmd *cmd;
73f22f62
JH
357 u8 scan;
358 int err;
359
360 cp = (void *) data;
73f22f62 361
4e51eae9 362 BT_DBG("request for hci%u", index);
73f22f62 363
bdce7baf
SJ
364 if (len != sizeof(*cp))
365 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
366
4e51eae9 367 hdev = hci_dev_get(index);
73f22f62 368 if (!hdev)
4e51eae9 369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
73f22f62
JH
370
371 hci_dev_lock_bh(hdev);
372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9 374 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
73f22f62
JH
375 goto failed;
376 }
377
4e51eae9
SJ
378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
380 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
73f22f62
JH
381 goto failed;
382 }
383
72a734ec 384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
73f22f62 385 test_bit(HCI_PSCAN, &hdev->flags)) {
4e51eae9 386 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
73f22f62
JH
387 goto failed;
388 }
389
4e51eae9 390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
366a0336
JH
391 if (!cmd) {
392 err = -ENOMEM;
73f22f62 393 goto failed;
366a0336 394 }
73f22f62
JH
395
396 scan = SCAN_PAGE;
397
72a734ec 398 if (cp->val)
73f22f62
JH
399 scan |= SCAN_INQUIRY;
400
401 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
402 if (err < 0)
a664b5bc 403 mgmt_pending_remove(cmd);
73f22f62
JH
404
405failed:
406 hci_dev_unlock_bh(hdev);
407 hci_dev_put(hdev);
408
409 return err;
410}
411
4e51eae9
SJ
412static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
413 u16 len)
9fbcbb45 414{
72a734ec 415 struct mgmt_mode *cp;
9fbcbb45 416 struct hci_dev *hdev;
366a0336 417 struct pending_cmd *cmd;
9fbcbb45
JH
418 u8 scan;
419 int err;
420
421 cp = (void *) data;
9fbcbb45 422
4e51eae9 423 BT_DBG("request for hci%u", index);
9fbcbb45 424
bdce7baf
SJ
425 if (len != sizeof(*cp))
426 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
427
4e51eae9 428 hdev = hci_dev_get(index);
9fbcbb45 429 if (!hdev)
4e51eae9 430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
9fbcbb45
JH
431
432 hci_dev_lock_bh(hdev);
433
434 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9 435 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
9fbcbb45
JH
436 goto failed;
437 }
438
4e51eae9
SJ
439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
9fbcbb45
JH
442 goto failed;
443 }
444
72a734ec 445 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
4e51eae9 446 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
9fbcbb45
JH
447 goto failed;
448 }
449
4e51eae9 450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
366a0336
JH
451 if (!cmd) {
452 err = -ENOMEM;
9fbcbb45 453 goto failed;
366a0336 454 }
9fbcbb45 455
72a734ec 456 if (cp->val)
9fbcbb45
JH
457 scan = SCAN_PAGE;
458 else
459 scan = 0;
460
461 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
462 if (err < 0)
a664b5bc 463 mgmt_pending_remove(cmd);
9fbcbb45
JH
464
465failed:
466 hci_dev_unlock_bh(hdev);
467 hci_dev_put(hdev);
468
469 return err;
470}
471
4e51eae9
SJ
472static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
473 struct sock *skip_sk)
c542a06c
JH
474{
475 struct sk_buff *skb;
476 struct mgmt_hdr *hdr;
477
478 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
479 if (!skb)
480 return -ENOMEM;
481
482 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
483
484 hdr = (void *) skb_put(skb, sizeof(*hdr));
485 hdr->opcode = cpu_to_le16(event);
4e51eae9 486 hdr->index = cpu_to_le16(index);
c542a06c
JH
487 hdr->len = cpu_to_le16(data_len);
488
4e51eae9
SJ
489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
c542a06c
JH
491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
053f0211
JH
498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
a38528f1 500 struct mgmt_mode rp;
053f0211 501
a38528f1 502 rp.val = val;
053f0211 503
4e51eae9 504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
053f0211
JH
505}
506
4e51eae9
SJ
507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
c542a06c
JH
509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
c542a06c
JH
512 int err;
513
514 cp = (void *) data;
c542a06c 515
4e51eae9 516 BT_DBG("request for hci%u", index);
c542a06c 517
bdce7baf
SJ
518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
4e51eae9 521 hdev = hci_dev_get(index);
c542a06c 522 if (!hdev)
4e51eae9 523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
c542a06c
JH
524
525 hci_dev_lock_bh(hdev);
526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
4e51eae9 532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
c542a06c
JH
533 if (err < 0)
534 goto failed;
535
c542a06c
JH
536 ev.val = cp->val;
537
4e51eae9 538 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
c542a06c
JH
539
540failed:
541 hci_dev_unlock_bh(hdev);
542 hci_dev_put(hdev);
543
544 return err;
545}
546
1aff6f09
JH
547static u8 get_service_classes(struct hci_dev *hdev)
548{
549 struct list_head *p;
550 u8 val = 0;
551
552 list_for_each(p, &hdev->uuids) {
553 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
554
555 val |= uuid->svc_hint;
556 }
557
558 return val;
559}
560
561static int update_class(struct hci_dev *hdev)
562{
563 u8 cod[3];
564
565 BT_DBG("%s", hdev->name);
566
567 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
568 return 0;
569
570 cod[0] = hdev->minor_class;
571 cod[1] = hdev->major_class;
572 cod[2] = get_service_classes(hdev);
573
574 if (memcmp(cod, hdev->dev_class, 3) == 0)
575 return 0;
576
577 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
578}
579
4e51eae9 580static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
2aeb9a1a
JH
581{
582 struct mgmt_cp_add_uuid *cp;
583 struct hci_dev *hdev;
584 struct bt_uuid *uuid;
2aeb9a1a
JH
585 int err;
586
587 cp = (void *) data;
2aeb9a1a 588
4e51eae9 589 BT_DBG("request for hci%u", index);
2aeb9a1a 590
bdce7baf
SJ
591 if (len != sizeof(*cp))
592 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
593
4e51eae9 594 hdev = hci_dev_get(index);
2aeb9a1a 595 if (!hdev)
4e51eae9 596 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
2aeb9a1a
JH
597
598 hci_dev_lock_bh(hdev);
599
600 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
601 if (!uuid) {
602 err = -ENOMEM;
603 goto failed;
604 }
605
606 memcpy(uuid->uuid, cp->uuid, 16);
1aff6f09 607 uuid->svc_hint = cp->svc_hint;
2aeb9a1a
JH
608
609 list_add(&uuid->list, &hdev->uuids);
610
1aff6f09
JH
611 err = update_class(hdev);
612 if (err < 0)
613 goto failed;
614
4e51eae9 615 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
2aeb9a1a
JH
616
617failed:
618 hci_dev_unlock_bh(hdev);
619 hci_dev_put(hdev);
620
621 return err;
622}
623
4e51eae9 624static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
2aeb9a1a
JH
625{
626 struct list_head *p, *n;
779cb850 627 struct mgmt_cp_remove_uuid *cp;
2aeb9a1a
JH
628 struct hci_dev *hdev;
629 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2aeb9a1a
JH
630 int err, found;
631
632 cp = (void *) data;
2aeb9a1a 633
4e51eae9 634 BT_DBG("request for hci%u", index);
2aeb9a1a 635
bdce7baf
SJ
636 if (len != sizeof(*cp))
637 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
638
4e51eae9 639 hdev = hci_dev_get(index);
2aeb9a1a 640 if (!hdev)
4e51eae9 641 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
2aeb9a1a
JH
642
643 hci_dev_lock_bh(hdev);
644
645 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
646 err = hci_uuids_clear(hdev);
647 goto unlock;
648 }
649
650 found = 0;
651
652 list_for_each_safe(p, n, &hdev->uuids) {
653 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
654
655 if (memcmp(match->uuid, cp->uuid, 16) != 0)
656 continue;
657
658 list_del(&match->list);
659 found++;
660 }
661
662 if (found == 0) {
4e51eae9 663 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
2aeb9a1a
JH
664 goto unlock;
665 }
666
1aff6f09
JH
667 err = update_class(hdev);
668 if (err < 0)
669 goto unlock;
670
4e51eae9 671 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
2aeb9a1a
JH
672
673unlock:
674 hci_dev_unlock_bh(hdev);
675 hci_dev_put(hdev);
676
677 return err;
678}
679
4e51eae9
SJ
680static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
681 u16 len)
1aff6f09
JH
682{
683 struct hci_dev *hdev;
684 struct mgmt_cp_set_dev_class *cp;
1aff6f09
JH
685 int err;
686
687 cp = (void *) data;
1aff6f09 688
4e51eae9 689 BT_DBG("request for hci%u", index);
1aff6f09 690
bdce7baf
SJ
691 if (len != sizeof(*cp))
692 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
693
4e51eae9 694 hdev = hci_dev_get(index);
1aff6f09 695 if (!hdev)
4e51eae9 696 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
1aff6f09
JH
697
698 hci_dev_lock_bh(hdev);
699
700 hdev->major_class = cp->major;
701 hdev->minor_class = cp->minor;
702
703 err = update_class(hdev);
704
705 if (err == 0)
4e51eae9 706 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
1aff6f09
JH
707
708 hci_dev_unlock_bh(hdev);
709 hci_dev_put(hdev);
710
711 return err;
712}
713
4e51eae9
SJ
714static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
715 u16 len)
1aff6f09
JH
716{
717 struct hci_dev *hdev;
718 struct mgmt_cp_set_service_cache *cp;
1aff6f09
JH
719 int err;
720
721 cp = (void *) data;
1aff6f09 722
bdce7baf 723 if (len != sizeof(*cp))
b8534e0f 724 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
bdce7baf 725
4e51eae9 726 hdev = hci_dev_get(index);
1aff6f09 727 if (!hdev)
4e51eae9 728 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1aff6f09
JH
729
730 hci_dev_lock_bh(hdev);
731
4e51eae9 732 BT_DBG("hci%u enable %d", index, cp->enable);
1aff6f09
JH
733
734 if (cp->enable) {
735 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
736 err = 0;
737 } else {
738 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
739 err = update_class(hdev);
740 }
741
742 if (err == 0)
4e51eae9
SJ
743 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
744 0);
1aff6f09
JH
745
746 hci_dev_unlock_bh(hdev);
747 hci_dev_put(hdev);
748
749 return err;
750}
751
4e51eae9 752static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
55ed8ca1
JH
753{
754 struct hci_dev *hdev;
755 struct mgmt_cp_load_keys *cp;
4e51eae9 756 u16 key_count, expected_len;
55ed8ca1
JH
757 int i;
758
759 cp = (void *) data;
bdce7baf
SJ
760
761 if (len < sizeof(*cp))
762 return -EINVAL;
763
55ed8ca1
JH
764 key_count = get_unaligned_le16(&cp->key_count);
765
766 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
767 if (expected_len != len) {
768 BT_ERR("load_keys: expected %u bytes, got %u bytes",
769 len, expected_len);
770 return -EINVAL;
771 }
772
4e51eae9 773 hdev = hci_dev_get(index);
55ed8ca1 774 if (!hdev)
4e51eae9 775 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
55ed8ca1 776
4e51eae9 777 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
55ed8ca1
JH
778 key_count);
779
780 hci_dev_lock_bh(hdev);
781
782 hci_link_keys_clear(hdev);
783
784 set_bit(HCI_LINK_KEYS, &hdev->flags);
785
786 if (cp->debug_keys)
787 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
788 else
789 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
790
791 for (i = 0; i < key_count; i++) {
792 struct mgmt_key_info *key = &cp->keys[i];
793
794 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
795 key->pin_len);
796 }
797
798 hci_dev_unlock_bh(hdev);
799 hci_dev_put(hdev);
800
801 return 0;
802}
803
4e51eae9 804static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
55ed8ca1
JH
805{
806 struct hci_dev *hdev;
807 struct mgmt_cp_remove_key *cp;
808 struct hci_conn *conn;
55ed8ca1
JH
809 int err;
810
811 cp = (void *) data;
55ed8ca1 812
bdce7baf
SJ
813 if (len != sizeof(*cp))
814 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
815
4e51eae9 816 hdev = hci_dev_get(index);
55ed8ca1 817 if (!hdev)
4e51eae9 818 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
55ed8ca1
JH
819
820 hci_dev_lock_bh(hdev);
821
822 err = hci_remove_link_key(hdev, &cp->bdaddr);
823 if (err < 0) {
4e51eae9 824 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
55ed8ca1
JH
825 goto unlock;
826 }
827
828 err = 0;
829
830 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
831 goto unlock;
832
833 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
834 if (conn) {
835 struct hci_cp_disconnect dc;
836
837 put_unaligned_le16(conn->handle, &dc.handle);
838 dc.reason = 0x13; /* Remote User Terminated Connection */
839 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
840 }
841
842unlock:
843 hci_dev_unlock_bh(hdev);
844 hci_dev_put(hdev);
845
846 return err;
847}
848
4e51eae9 849static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
8962ee74
JH
850{
851 struct hci_dev *hdev;
852 struct mgmt_cp_disconnect *cp;
853 struct hci_cp_disconnect dc;
366a0336 854 struct pending_cmd *cmd;
8962ee74 855 struct hci_conn *conn;
8962ee74
JH
856 int err;
857
858 BT_DBG("");
859
860 cp = (void *) data;
8962ee74 861
bdce7baf
SJ
862 if (len != sizeof(*cp))
863 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
864
4e51eae9 865 hdev = hci_dev_get(index);
8962ee74 866 if (!hdev)
4e51eae9 867 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
8962ee74
JH
868
869 hci_dev_lock_bh(hdev);
870
871 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9 872 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
8962ee74
JH
873 goto failed;
874 }
875
4e51eae9
SJ
876 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
877 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
8962ee74
JH
878 goto failed;
879 }
880
881 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
882 if (!conn) {
4e51eae9 883 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
8962ee74
JH
884 goto failed;
885 }
886
4e51eae9 887 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
366a0336
JH
888 if (!cmd) {
889 err = -ENOMEM;
8962ee74 890 goto failed;
366a0336 891 }
8962ee74
JH
892
893 put_unaligned_le16(conn->handle, &dc.handle);
894 dc.reason = 0x13; /* Remote User Terminated Connection */
895
896 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
897 if (err < 0)
a664b5bc 898 mgmt_pending_remove(cmd);
8962ee74
JH
899
900failed:
901 hci_dev_unlock_bh(hdev);
902 hci_dev_put(hdev);
903
904 return err;
905}
906
8ce6284e 907static int get_connections(struct sock *sk, u16 index)
2784eb41 908{
2784eb41
JH
909 struct mgmt_rp_get_connections *rp;
910 struct hci_dev *hdev;
911 struct list_head *p;
a38528f1 912 size_t rp_len;
4e51eae9 913 u16 count;
2784eb41
JH
914 int i, err;
915
916 BT_DBG("");
917
4e51eae9 918 hdev = hci_dev_get(index);
2784eb41 919 if (!hdev)
4e51eae9 920 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
2784eb41
JH
921
922 hci_dev_lock_bh(hdev);
923
924 count = 0;
925 list_for_each(p, &hdev->conn_hash.list) {
926 count++;
927 }
928
a38528f1
JH
929 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
930 rp = kmalloc(rp_len, GFP_ATOMIC);
931 if (!rp) {
2784eb41
JH
932 err = -ENOMEM;
933 goto unlock;
934 }
935
2784eb41
JH
936 put_unaligned_le16(count, &rp->conn_count);
937
938 read_lock(&hci_dev_list_lock);
939
940 i = 0;
941 list_for_each(p, &hdev->conn_hash.list) {
942 struct hci_conn *c = list_entry(p, struct hci_conn, list);
943
944 bacpy(&rp->conn[i++], &c->dst);
945 }
946
947 read_unlock(&hci_dev_list_lock);
948
4e51eae9 949 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
2784eb41
JH
950
951unlock:
a38528f1 952 kfree(rp);
2784eb41
JH
953 hci_dev_unlock_bh(hdev);
954 hci_dev_put(hdev);
955 return err;
956}
957
4e51eae9
SJ
958static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
959 u16 len)
980e1a53
JH
960{
961 struct hci_dev *hdev;
962 struct mgmt_cp_pin_code_reply *cp;
963 struct hci_cp_pin_code_reply reply;
366a0336 964 struct pending_cmd *cmd;
980e1a53
JH
965 int err;
966
967 BT_DBG("");
968
969 cp = (void *) data;
980e1a53 970
bdce7baf
SJ
971 if (len != sizeof(*cp))
972 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
973
4e51eae9 974 hdev = hci_dev_get(index);
980e1a53 975 if (!hdev)
4e51eae9 976 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
980e1a53
JH
977
978 hci_dev_lock_bh(hdev);
979
980 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9 981 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
980e1a53
JH
982 goto failed;
983 }
984
4e51eae9 985 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
366a0336
JH
986 if (!cmd) {
987 err = -ENOMEM;
980e1a53 988 goto failed;
366a0336 989 }
980e1a53
JH
990
991 bacpy(&reply.bdaddr, &cp->bdaddr);
992 reply.pin_len = cp->pin_len;
993 memcpy(reply.pin_code, cp->pin_code, 16);
994
995 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
996 if (err < 0)
a664b5bc 997 mgmt_pending_remove(cmd);
980e1a53
JH
998
999failed:
1000 hci_dev_unlock_bh(hdev);
1001 hci_dev_put(hdev);
1002
1003 return err;
1004}
1005
4e51eae9
SJ
1006static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1007 u16 len)
980e1a53
JH
1008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_pin_code_neg_reply *cp;
366a0336 1011 struct pending_cmd *cmd;
980e1a53
JH
1012 int err;
1013
1014 BT_DBG("");
1015
1016 cp = (void *) data;
980e1a53 1017
bdce7baf
SJ
1018 if (len != sizeof(*cp))
1019 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1020 EINVAL);
1021
4e51eae9 1022 hdev = hci_dev_get(index);
980e1a53 1023 if (!hdev)
4e51eae9
SJ
1024 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1025 ENODEV);
980e1a53
JH
1026
1027 hci_dev_lock_bh(hdev);
1028
1029 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9
SJ
1030 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1031 ENETDOWN);
980e1a53
JH
1032 goto failed;
1033 }
1034
4e51eae9 1035 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
980e1a53 1036 data, len);
366a0336
JH
1037 if (!cmd) {
1038 err = -ENOMEM;
980e1a53 1039 goto failed;
366a0336 1040 }
980e1a53 1041
3cf2a4f6 1042 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
980e1a53
JH
1043 &cp->bdaddr);
1044 if (err < 0)
a664b5bc 1045 mgmt_pending_remove(cmd);
980e1a53
JH
1046
1047failed:
1048 hci_dev_unlock_bh(hdev);
1049 hci_dev_put(hdev);
1050
1051 return err;
1052}
1053
4e51eae9
SJ
1054static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1055 u16 len)
17fa4b9d
JH
1056{
1057 struct hci_dev *hdev;
1058 struct mgmt_cp_set_io_capability *cp;
17fa4b9d
JH
1059
1060 BT_DBG("");
1061
1062 cp = (void *) data;
17fa4b9d 1063
bdce7baf 1064 if (len != sizeof(*cp))
b8534e0f 1065 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
bdce7baf 1066
4e51eae9 1067 hdev = hci_dev_get(index);
17fa4b9d 1068 if (!hdev)
4e51eae9 1069 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
17fa4b9d
JH
1070
1071 hci_dev_lock_bh(hdev);
1072
1073 hdev->io_capability = cp->io_capability;
1074
1075 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
b8534e0f 1076 hdev->io_capability);
17fa4b9d
JH
1077
1078 hci_dev_unlock_bh(hdev);
1079 hci_dev_put(hdev);
1080
4e51eae9 1081 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
17fa4b9d
JH
1082}
1083
e9a416b5
JH
1084static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1085{
1086 struct hci_dev *hdev = conn->hdev;
1087 struct list_head *p;
1088
1089 list_for_each(p, &cmd_list) {
1090 struct pending_cmd *cmd;
1091
1092 cmd = list_entry(p, struct pending_cmd, list);
1093
1094 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1095 continue;
1096
1097 if (cmd->index != hdev->id)
1098 continue;
1099
1100 if (cmd->user_data != conn)
1101 continue;
1102
1103 return cmd;
1104 }
1105
1106 return NULL;
1107}
1108
1109static void pairing_complete(struct pending_cmd *cmd, u8 status)
1110{
1111 struct mgmt_rp_pair_device rp;
1112 struct hci_conn *conn = cmd->user_data;
1113
e9a416b5
JH
1114 bacpy(&rp.bdaddr, &conn->dst);
1115 rp.status = status;
1116
4e51eae9 1117 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
e9a416b5
JH
1118
1119 /* So we don't get further callbacks for this connection */
1120 conn->connect_cfm_cb = NULL;
1121 conn->security_cfm_cb = NULL;
1122 conn->disconn_cfm_cb = NULL;
1123
1124 hci_conn_put(conn);
1125
a664b5bc 1126 mgmt_pending_remove(cmd);
e9a416b5
JH
1127}
1128
1129static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1130{
1131 struct pending_cmd *cmd;
1132
1133 BT_DBG("status %u", status);
1134
1135 cmd = find_pairing(conn);
1136 if (!cmd) {
1137 BT_DBG("Unable to find a pending command");
1138 return;
1139 }
1140
1141 pairing_complete(cmd, status);
1142}
1143
4e51eae9 1144static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
e9a416b5
JH
1145{
1146 struct hci_dev *hdev;
1147 struct mgmt_cp_pair_device *cp;
1148 struct pending_cmd *cmd;
1149 u8 sec_level, auth_type;
1150 struct hci_conn *conn;
e9a416b5
JH
1151 int err;
1152
1153 BT_DBG("");
1154
1155 cp = (void *) data;
e9a416b5 1156
bdce7baf
SJ
1157 if (len != sizeof(*cp))
1158 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1159
4e51eae9 1160 hdev = hci_dev_get(index);
e9a416b5 1161 if (!hdev)
4e51eae9 1162 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
e9a416b5
JH
1163
1164 hci_dev_lock_bh(hdev);
1165
1166 if (cp->io_cap == 0x03) {
1167 sec_level = BT_SECURITY_MEDIUM;
1168 auth_type = HCI_AT_DEDICATED_BONDING;
1169 } else {
1170 sec_level = BT_SECURITY_HIGH;
1171 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1172 }
1173
1174 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
30e76272
VT
1175 if (IS_ERR(conn)) {
1176 err = PTR_ERR(conn);
e9a416b5
JH
1177 goto unlock;
1178 }
1179
1180 if (conn->connect_cfm_cb) {
1181 hci_conn_put(conn);
4e51eae9 1182 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
e9a416b5
JH
1183 goto unlock;
1184 }
1185
4e51eae9 1186 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
e9a416b5
JH
1187 if (!cmd) {
1188 err = -ENOMEM;
1189 hci_conn_put(conn);
1190 goto unlock;
1191 }
1192
1193 conn->connect_cfm_cb = pairing_complete_cb;
1194 conn->security_cfm_cb = pairing_complete_cb;
1195 conn->disconn_cfm_cb = pairing_complete_cb;
1196 conn->io_capability = cp->io_cap;
1197 cmd->user_data = conn;
1198
1199 if (conn->state == BT_CONNECTED &&
1200 hci_conn_security(conn, sec_level, auth_type))
1201 pairing_complete(cmd, 0);
1202
1203 err = 0;
1204
1205unlock:
1206 hci_dev_unlock_bh(hdev);
1207 hci_dev_put(hdev);
1208
1209 return err;
1210}
1211
4e51eae9
SJ
1212static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1213 u16 len, int success)
a5c29683
JH
1214{
1215 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
4e51eae9 1216 u16 mgmt_op, hci_op;
a5c29683
JH
1217 struct pending_cmd *cmd;
1218 struct hci_dev *hdev;
1219 int err;
1220
1221 BT_DBG("");
1222
a5c29683
JH
1223 if (success) {
1224 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1225 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1226 } else {
1227 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1228 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1229 }
1230
bdce7baf
SJ
1231 if (len != sizeof(*cp))
1232 return cmd_status(sk, index, mgmt_op, EINVAL);
1233
4e51eae9 1234 hdev = hci_dev_get(index);
a5c29683 1235 if (!hdev)
4e51eae9 1236 return cmd_status(sk, index, mgmt_op, ENODEV);
a5c29683
JH
1237
1238 if (!test_bit(HCI_UP, &hdev->flags)) {
4e51eae9 1239 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
a5c29683
JH
1240 goto failed;
1241 }
1242
4e51eae9 1243 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
a5c29683
JH
1244 if (!cmd) {
1245 err = -ENOMEM;
1246 goto failed;
1247 }
1248
1249 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
a664b5bc
JH
1250 if (err < 0)
1251 mgmt_pending_remove(cmd);
a5c29683
JH
1252
1253failed:
1254 hci_dev_unlock_bh(hdev);
1255 hci_dev_put(hdev);
1256
1257 return err;
1258}
1259
b312b161
JH
1260static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1261 u16 len)
1262{
1263 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1264 struct hci_cp_write_local_name hci_cp;
1265 struct hci_dev *hdev;
1266 struct pending_cmd *cmd;
1267 int err;
1268
1269 BT_DBG("");
1270
1271 if (len != sizeof(*mgmt_cp))
1272 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1273
1274 hdev = hci_dev_get(index);
1275 if (!hdev)
1276 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1277
1278 hci_dev_lock_bh(hdev);
1279
1280 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1281 if (!cmd) {
1282 err = -ENOMEM;
1283 goto failed;
1284 }
1285
1286 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1287 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1288 &hci_cp);
1289 if (err < 0)
1290 mgmt_pending_remove(cmd);
1291
1292failed:
1293 hci_dev_unlock_bh(hdev);
1294 hci_dev_put(hdev);
1295
1296 return err;
1297}
1298
c35938b2
SJ
1299static int read_local_oob_data(struct sock *sk, u16 index)
1300{
1301 struct hci_dev *hdev;
1302 struct pending_cmd *cmd;
1303 int err;
1304
1305 BT_DBG("hci%u", index);
1306
1307 hdev = hci_dev_get(index);
1308 if (!hdev)
1309 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1310 ENODEV);
1311
1312 hci_dev_lock_bh(hdev);
1313
1314 if (!test_bit(HCI_UP, &hdev->flags)) {
1315 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1316 ENETDOWN);
1317 goto unlock;
1318 }
1319
1320 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1321 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1322 EOPNOTSUPP);
1323 goto unlock;
1324 }
1325
1326 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1327 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1328 goto unlock;
1329 }
1330
1331 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1332 if (!cmd) {
1333 err = -ENOMEM;
1334 goto unlock;
1335 }
1336
1337 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1338 if (err < 0)
1339 mgmt_pending_remove(cmd);
1340
1341unlock:
1342 hci_dev_unlock_bh(hdev);
1343 hci_dev_put(hdev);
1344
1345 return err;
1346}
1347
0381101f
JH
1348int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1349{
1350 unsigned char *buf;
1351 struct mgmt_hdr *hdr;
4e51eae9 1352 u16 opcode, index, len;
0381101f
JH
1353 int err;
1354
1355 BT_DBG("got %zu bytes", msglen);
1356
1357 if (msglen < sizeof(*hdr))
1358 return -EINVAL;
1359
1360 buf = kmalloc(msglen, GFP_ATOMIC);
1361 if (!buf)
1362 return -ENOMEM;
1363
1364 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1365 err = -EFAULT;
1366 goto done;
1367 }
1368
1369 hdr = (struct mgmt_hdr *) buf;
1370 opcode = get_unaligned_le16(&hdr->opcode);
4e51eae9 1371 index = get_unaligned_le16(&hdr->index);
0381101f
JH
1372 len = get_unaligned_le16(&hdr->len);
1373
1374 if (len != msglen - sizeof(*hdr)) {
1375 err = -EINVAL;
1376 goto done;
1377 }
1378
1379 switch (opcode) {
02d98129
JH
1380 case MGMT_OP_READ_VERSION:
1381 err = read_version(sk);
1382 break;
faba42eb
JH
1383 case MGMT_OP_READ_INDEX_LIST:
1384 err = read_index_list(sk);
1385 break;
f7b64e69 1386 case MGMT_OP_READ_INFO:
4e51eae9 1387 err = read_controller_info(sk, index);
f7b64e69 1388 break;
eec8d2bc 1389 case MGMT_OP_SET_POWERED:
4e51eae9 1390 err = set_powered(sk, index, buf + sizeof(*hdr), len);
eec8d2bc 1391 break;
73f22f62 1392 case MGMT_OP_SET_DISCOVERABLE:
4e51eae9 1393 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
73f22f62 1394 break;
9fbcbb45 1395 case MGMT_OP_SET_CONNECTABLE:
4e51eae9 1396 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
9fbcbb45 1397 break;
c542a06c 1398 case MGMT_OP_SET_PAIRABLE:
4e51eae9 1399 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
c542a06c 1400 break;
2aeb9a1a 1401 case MGMT_OP_ADD_UUID:
4e51eae9 1402 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
2aeb9a1a
JH
1403 break;
1404 case MGMT_OP_REMOVE_UUID:
4e51eae9 1405 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
2aeb9a1a 1406 break;
1aff6f09 1407 case MGMT_OP_SET_DEV_CLASS:
4e51eae9 1408 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
1aff6f09
JH
1409 break;
1410 case MGMT_OP_SET_SERVICE_CACHE:
4e51eae9 1411 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
1aff6f09 1412 break;
55ed8ca1 1413 case MGMT_OP_LOAD_KEYS:
4e51eae9 1414 err = load_keys(sk, index, buf + sizeof(*hdr), len);
55ed8ca1
JH
1415 break;
1416 case MGMT_OP_REMOVE_KEY:
4e51eae9 1417 err = remove_key(sk, index, buf + sizeof(*hdr), len);
55ed8ca1 1418 break;
8962ee74 1419 case MGMT_OP_DISCONNECT:
4e51eae9 1420 err = disconnect(sk, index, buf + sizeof(*hdr), len);
8962ee74 1421 break;
2784eb41 1422 case MGMT_OP_GET_CONNECTIONS:
8ce6284e 1423 err = get_connections(sk, index);
2784eb41 1424 break;
980e1a53 1425 case MGMT_OP_PIN_CODE_REPLY:
4e51eae9 1426 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
980e1a53
JH
1427 break;
1428 case MGMT_OP_PIN_CODE_NEG_REPLY:
4e51eae9 1429 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
980e1a53 1430 break;
17fa4b9d 1431 case MGMT_OP_SET_IO_CAPABILITY:
4e51eae9 1432 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
17fa4b9d 1433 break;
e9a416b5 1434 case MGMT_OP_PAIR_DEVICE:
4e51eae9 1435 err = pair_device(sk, index, buf + sizeof(*hdr), len);
e9a416b5 1436 break;
a5c29683 1437 case MGMT_OP_USER_CONFIRM_REPLY:
4e51eae9 1438 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
a5c29683
JH
1439 break;
1440 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
4e51eae9 1441 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
a5c29683 1442 break;
b312b161
JH
1443 case MGMT_OP_SET_LOCAL_NAME:
1444 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1445 break;
c35938b2
SJ
1446 case MGMT_OP_READ_LOCAL_OOB_DATA:
1447 err = read_local_oob_data(sk, index);
1448 break;
1449
0381101f
JH
1450 default:
1451 BT_DBG("Unknown op %u", opcode);
4e51eae9 1452 err = cmd_status(sk, index, opcode, 0x01);
0381101f
JH
1453 break;
1454 }
1455
e41d8b4e
JH
1456 if (err < 0)
1457 goto done;
1458
0381101f
JH
1459 err = msglen;
1460
1461done:
1462 kfree(buf);
1463 return err;
1464}
c71e97bf 1465
c71e97bf
JH
1466int mgmt_index_added(u16 index)
1467{
4e51eae9 1468 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
c71e97bf
JH
1469}
1470
1471int mgmt_index_removed(u16 index)
1472{
4e51eae9 1473 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
eec8d2bc
JH
1474}
1475
73f22f62 1476struct cmd_lookup {
72a734ec 1477 u8 val;
eec8d2bc
JH
1478 struct sock *sk;
1479};
1480
72a734ec 1481static void mode_rsp(struct pending_cmd *cmd, void *data)
eec8d2bc 1482{
c68fb7ff 1483 struct mgmt_mode *cp = cmd->param;
73f22f62 1484 struct cmd_lookup *match = data;
eec8d2bc 1485
72a734ec 1486 if (cp->val != match->val)
eec8d2bc
JH
1487 return;
1488
053f0211 1489 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
eec8d2bc
JH
1490
1491 list_del(&cmd->list);
1492
1493 if (match->sk == NULL) {
1494 match->sk = cmd->sk;
1495 sock_hold(match->sk);
1496 }
1497
1498 mgmt_pending_free(cmd);
c71e97bf 1499}
5add6af8
JH
1500
1501int mgmt_powered(u16 index, u8 powered)
1502{
72a734ec 1503 struct mgmt_mode ev;
73f22f62 1504 struct cmd_lookup match = { powered, NULL };
eec8d2bc 1505 int ret;
5add6af8 1506
72a734ec 1507 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
5add6af8 1508
72a734ec 1509 ev.val = powered;
eec8d2bc 1510
4e51eae9 1511 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
eec8d2bc
JH
1512
1513 if (match.sk)
1514 sock_put(match.sk);
1515
1516 return ret;
5add6af8 1517}
73f22f62 1518
73f22f62
JH
1519int mgmt_discoverable(u16 index, u8 discoverable)
1520{
72a734ec 1521 struct mgmt_mode ev;
73f22f62
JH
1522 struct cmd_lookup match = { discoverable, NULL };
1523 int ret;
1524
b8534e0f 1525 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
72a734ec 1526
72a734ec 1527 ev.val = discoverable;
73f22f62 1528
4e51eae9
SJ
1529 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1530 match.sk);
73f22f62
JH
1531
1532 if (match.sk)
1533 sock_put(match.sk);
1534
1535 return ret;
1536}
9fbcbb45 1537
9fbcbb45
JH
1538int mgmt_connectable(u16 index, u8 connectable)
1539{
72a734ec 1540 struct mgmt_mode ev;
9fbcbb45
JH
1541 struct cmd_lookup match = { connectable, NULL };
1542 int ret;
1543
72a734ec 1544 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
9fbcbb45 1545
72a734ec 1546 ev.val = connectable;
9fbcbb45 1547
4e51eae9 1548 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
9fbcbb45
JH
1549
1550 if (match.sk)
1551 sock_put(match.sk);
1552
1553 return ret;
1554}
55ed8ca1
JH
1555
1556int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1557{
1558 struct mgmt_ev_new_key ev;
1559
1560 memset(&ev, 0, sizeof(ev));
1561
55ed8ca1
JH
1562 bacpy(&ev.key.bdaddr, &key->bdaddr);
1563 ev.key.type = key->type;
1564 memcpy(ev.key.val, key->val, 16);
1565 ev.key.pin_len = key->pin_len;
1566 ev.old_key_type = old_key_type;
1567
4e51eae9 1568 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
55ed8ca1 1569}
f7520543
JH
1570
1571int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1572{
1573 struct mgmt_ev_connected ev;
1574
f7520543
JH
1575 bacpy(&ev.bdaddr, bdaddr);
1576
4e51eae9 1577 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
f7520543
JH
1578}
1579
8962ee74
JH
1580static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1581{
c68fb7ff 1582 struct mgmt_cp_disconnect *cp = cmd->param;
8962ee74 1583 struct sock **sk = data;
a38528f1 1584 struct mgmt_rp_disconnect rp;
8962ee74 1585
a38528f1 1586 bacpy(&rp.bdaddr, &cp->bdaddr);
8962ee74 1587
4e51eae9 1588 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
8962ee74
JH
1589
1590 *sk = cmd->sk;
1591 sock_hold(*sk);
1592
a664b5bc 1593 mgmt_pending_remove(cmd);
8962ee74
JH
1594}
1595
f7520543
JH
1596int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1597{
1598 struct mgmt_ev_disconnected ev;
8962ee74
JH
1599 struct sock *sk = NULL;
1600 int err;
1601
1602 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
f7520543 1603
f7520543
JH
1604 bacpy(&ev.bdaddr, bdaddr);
1605
4e51eae9 1606 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
8962ee74
JH
1607
1608 if (sk)
1609 sock_put(sk);
1610
1611 return err;
1612}
1613
1614int mgmt_disconnect_failed(u16 index)
1615{
1616 struct pending_cmd *cmd;
1617 int err;
1618
1619 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1620 if (!cmd)
1621 return -ENOENT;
1622
4e51eae9 1623 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
8962ee74 1624
a664b5bc 1625 mgmt_pending_remove(cmd);
8962ee74
JH
1626
1627 return err;
f7520543 1628}
17d5c04c
JH
1629
1630int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1631{
1632 struct mgmt_ev_connect_failed ev;
1633
17d5c04c
JH
1634 bacpy(&ev.bdaddr, bdaddr);
1635 ev.status = status;
1636
4e51eae9 1637 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
17d5c04c 1638}
980e1a53
JH
1639
1640int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1641{
1642 struct mgmt_ev_pin_code_request ev;
1643
980e1a53
JH
1644 bacpy(&ev.bdaddr, bdaddr);
1645
4e51eae9
SJ
1646 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1647 NULL);
980e1a53
JH
1648}
1649
1650int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1651{
1652 struct pending_cmd *cmd;
ac56fb13 1653 struct mgmt_rp_pin_code_reply rp;
980e1a53
JH
1654 int err;
1655
1656 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1657 if (!cmd)
1658 return -ENOENT;
1659
ac56fb13
JH
1660 bacpy(&rp.bdaddr, bdaddr);
1661 rp.status = status;
1662
4e51eae9
SJ
1663 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1664 sizeof(rp));
980e1a53 1665
a664b5bc 1666 mgmt_pending_remove(cmd);
980e1a53
JH
1667
1668 return err;
1669}
1670
1671int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1672{
1673 struct pending_cmd *cmd;
ac56fb13 1674 struct mgmt_rp_pin_code_reply rp;
980e1a53
JH
1675 int err;
1676
1677 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1678 if (!cmd)
1679 return -ENOENT;
1680
ac56fb13
JH
1681 bacpy(&rp.bdaddr, bdaddr);
1682 rp.status = status;
1683
4e51eae9
SJ
1684 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1685 sizeof(rp));
980e1a53 1686
a664b5bc 1687 mgmt_pending_remove(cmd);
980e1a53
JH
1688
1689 return err;
1690}
a5c29683
JH
1691
1692int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1693{
1694 struct mgmt_ev_user_confirm_request ev;
1695
1696 BT_DBG("hci%u", index);
1697
a5c29683
JH
1698 bacpy(&ev.bdaddr, bdaddr);
1699 put_unaligned_le32(value, &ev.value);
1700
4e51eae9
SJ
1701 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1702 NULL);
a5c29683
JH
1703}
1704
1705static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1706 u8 opcode)
1707{
1708 struct pending_cmd *cmd;
1709 struct mgmt_rp_user_confirm_reply rp;
1710 int err;
1711
1712 cmd = mgmt_pending_find(opcode, index);
1713 if (!cmd)
1714 return -ENOENT;
1715
a5c29683
JH
1716 bacpy(&rp.bdaddr, bdaddr);
1717 rp.status = status;
4e51eae9 1718 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
a5c29683 1719
a664b5bc 1720 mgmt_pending_remove(cmd);
a5c29683
JH
1721
1722 return err;
1723}
1724
1725int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1726{
1727 return confirm_reply_complete(index, bdaddr, status,
1728 MGMT_OP_USER_CONFIRM_REPLY);
1729}
1730
b8534e0f 1731int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
a5c29683
JH
1732{
1733 return confirm_reply_complete(index, bdaddr, status,
1734 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1735}
2a611692
JH
1736
1737int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1738{
1739 struct mgmt_ev_auth_failed ev;
1740
2a611692
JH
1741 bacpy(&ev.bdaddr, bdaddr);
1742 ev.status = status;
1743
4e51eae9 1744 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
2a611692 1745}
b312b161
JH
1746
1747int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
1748{
1749 struct pending_cmd *cmd;
1750 struct mgmt_cp_set_local_name ev;
1751 int err;
1752
1753 memset(&ev, 0, sizeof(ev));
1754 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
1755
1756 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
1757 if (!cmd)
1758 goto send_event;
1759
1760 if (status) {
1761 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
1762 goto failed;
1763 }
1764
1765 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
1766 sizeof(ev));
1767 if (err < 0)
1768 goto failed;
1769
1770send_event:
1771 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
1772 cmd ? cmd->sk : NULL);
1773
1774failed:
1775 if (cmd)
1776 mgmt_pending_remove(cmd);
1777 return err;
1778}
c35938b2
SJ
1779
1780int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
1781 u8 status)
1782{
1783 struct pending_cmd *cmd;
1784 int err;
1785
1786 BT_DBG("hci%u status %u", index, status);
1787
1788 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
1789 if (!cmd)
1790 return -ENOENT;
1791
1792 if (status) {
1793 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1794 EIO);
1795 } else {
1796 struct mgmt_rp_read_local_oob_data rp;
1797
1798 memcpy(rp.hash, hash, sizeof(rp.hash));
1799 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
1800
1801 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1802 &rp, sizeof(rp));
1803 }
1804
1805 mgmt_pending_remove(cmd);
1806
1807 return err;
1808}
This page took 0.132675 seconds and 5 git commands to generate.