d10735076a25c389c25b7c202de2dc233a2ff274
[deliverable/linux.git] / net / bluetooth / mgmt.c
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
25 #include <asm/uaccess.h>
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
32 #define MGMT_VERSION 0
33 #define MGMT_REVISION 1
34
35 struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
41 };
42
43 LIST_HEAD(cmd_list);
44
45 static int cmd_status(struct sock *sk, u16 cmd, u8 status)
46 {
47 struct sk_buff *skb;
48 struct mgmt_hdr *hdr;
49 struct mgmt_ev_cmd_status *ev;
50
51 BT_DBG("sock %p", sk);
52
53 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
54 if (!skb)
55 return -ENOMEM;
56
57 hdr = (void *) skb_put(skb, sizeof(*hdr));
58
59 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
60 hdr->len = cpu_to_le16(sizeof(*ev));
61
62 ev = (void *) skb_put(skb, sizeof(*ev));
63 ev->status = status;
64 put_unaligned_le16(cmd, &ev->opcode);
65
66 if (sock_queue_rcv_skb(sk, skb) < 0)
67 kfree_skb(skb);
68
69 return 0;
70 }
71
72 static int read_version(struct sock *sk)
73 {
74 struct sk_buff *skb;
75 struct mgmt_hdr *hdr;
76 struct mgmt_ev_cmd_complete *ev;
77 struct mgmt_rp_read_version *rp;
78
79 BT_DBG("sock %p", sk);
80
81 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
82 if (!skb)
83 return -ENOMEM;
84
85 hdr = (void *) skb_put(skb, sizeof(*hdr));
86 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
87 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
88
89 ev = (void *) skb_put(skb, sizeof(*ev));
90 put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
91
92 rp = (void *) skb_put(skb, sizeof(*rp));
93 rp->version = MGMT_VERSION;
94 put_unaligned_le16(MGMT_REVISION, &rp->revision);
95
96 if (sock_queue_rcv_skb(sk, skb) < 0)
97 kfree_skb(skb);
98
99 return 0;
100 }
101
102 static int read_index_list(struct sock *sk)
103 {
104 struct sk_buff *skb;
105 struct mgmt_hdr *hdr;
106 struct mgmt_ev_cmd_complete *ev;
107 struct mgmt_rp_read_index_list *rp;
108 struct list_head *p;
109 size_t body_len;
110 u16 count;
111 int i;
112
113 BT_DBG("sock %p", sk);
114
115 read_lock(&hci_dev_list_lock);
116
117 count = 0;
118 list_for_each(p, &hci_dev_list) {
119 count++;
120 }
121
122 body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
123 skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
124 if (!skb) {
125 read_unlock(&hci_dev_list_lock);
126 return -ENOMEM;
127 }
128
129 hdr = (void *) skb_put(skb, sizeof(*hdr));
130 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
131 hdr->len = cpu_to_le16(body_len);
132
133 ev = (void *) skb_put(skb, sizeof(*ev));
134 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
135
136 rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
137 put_unaligned_le16(count, &rp->num_controllers);
138
139 i = 0;
140 list_for_each(p, &hci_dev_list) {
141 struct hci_dev *d = list_entry(p, struct hci_dev, list);
142
143 hci_del_off_timer(d);
144
145 set_bit(HCI_MGMT, &d->flags);
146
147 if (test_bit(HCI_SETUP, &d->flags))
148 continue;
149
150 put_unaligned_le16(d->id, &rp->index[i++]);
151 BT_DBG("Added hci%u", d->id);
152 }
153
154 read_unlock(&hci_dev_list_lock);
155
156 if (sock_queue_rcv_skb(sk, skb) < 0)
157 kfree_skb(skb);
158
159 return 0;
160 }
161
162 static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
163 {
164 struct sk_buff *skb;
165 struct mgmt_hdr *hdr;
166 struct mgmt_ev_cmd_complete *ev;
167 struct mgmt_rp_read_info *rp;
168 struct mgmt_cp_read_info *cp;
169 struct hci_dev *hdev;
170 u16 dev_id;
171
172 BT_DBG("sock %p", sk);
173
174 if (len != 2)
175 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
176
177 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
178 if (!skb)
179 return -ENOMEM;
180
181 hdr = (void *) skb_put(skb, sizeof(*hdr));
182 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
183 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
184
185 ev = (void *) skb_put(skb, sizeof(*ev));
186 put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
187
188 rp = (void *) skb_put(skb, sizeof(*rp));
189
190 cp = (void *) data;
191 dev_id = get_unaligned_le16(&cp->index);
192
193 BT_DBG("request for hci%u", dev_id);
194
195 hdev = hci_dev_get(dev_id);
196 if (!hdev) {
197 kfree_skb(skb);
198 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
199 }
200
201 hci_del_off_timer(hdev);
202
203 hci_dev_lock_bh(hdev);
204
205 set_bit(HCI_MGMT, &hdev->flags);
206
207 put_unaligned_le16(hdev->id, &rp->index);
208 rp->type = hdev->dev_type;
209
210 rp->powered = test_bit(HCI_UP, &hdev->flags);
211 rp->connectable = test_bit(HCI_PSCAN, &hdev->flags);
212 rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
213 rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
214
215 if (test_bit(HCI_AUTH, &hdev->flags))
216 rp->sec_mode = 3;
217 else if (hdev->ssp_mode > 0)
218 rp->sec_mode = 4;
219 else
220 rp->sec_mode = 2;
221
222 bacpy(&rp->bdaddr, &hdev->bdaddr);
223 memcpy(rp->features, hdev->features, 8);
224 memcpy(rp->dev_class, hdev->dev_class, 3);
225 put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
226 rp->hci_ver = hdev->hci_ver;
227 put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
228
229 hci_dev_unlock_bh(hdev);
230 hci_dev_put(hdev);
231
232 if (sock_queue_rcv_skb(sk, skb) < 0)
233 kfree_skb(skb);
234
235 return 0;
236 }
237
238 static void mgmt_pending_free(struct pending_cmd *cmd)
239 {
240 sock_put(cmd->sk);
241 kfree(cmd->cmd);
242 kfree(cmd);
243 }
244
245 static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
246 void *data, u16 len)
247 {
248 struct pending_cmd *cmd;
249
250 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
251 if (!cmd)
252 return -ENOMEM;
253
254 cmd->opcode = opcode;
255 cmd->index = index;
256
257 cmd->cmd = kmalloc(len, GFP_ATOMIC);
258 if (!cmd->cmd) {
259 kfree(cmd);
260 return -ENOMEM;
261 }
262
263 memcpy(cmd->cmd, data, len);
264
265 cmd->sk = sk;
266 sock_hold(sk);
267
268 list_add(&cmd->list, &cmd_list);
269
270 return 0;
271 }
272
273 static void mgmt_pending_foreach(u16 opcode, int index,
274 void (*cb)(struct pending_cmd *cmd, void *data),
275 void *data)
276 {
277 struct list_head *p, *n;
278
279 list_for_each_safe(p, n, &cmd_list) {
280 struct pending_cmd *cmd;
281
282 cmd = list_entry(p, struct pending_cmd, list);
283
284 if (cmd->opcode != opcode)
285 continue;
286
287 if (index >= 0 && cmd->index != index)
288 continue;
289
290 cb(cmd, data);
291 }
292 }
293
294 static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
295 {
296 struct list_head *p;
297
298 list_for_each(p, &cmd_list) {
299 struct pending_cmd *cmd;
300
301 cmd = list_entry(p, struct pending_cmd, list);
302
303 if (cmd->opcode != opcode)
304 continue;
305
306 if (index >= 0 && cmd->index != index)
307 continue;
308
309 return cmd;
310 }
311
312 return NULL;
313 }
314
315 static void mgmt_pending_remove(u16 opcode, int index)
316 {
317 struct pending_cmd *cmd;
318
319 cmd = mgmt_pending_find(opcode, index);
320 if (cmd == NULL)
321 return;
322
323 list_del(&cmd->list);
324 mgmt_pending_free(cmd);
325 }
326
327 static int set_powered(struct sock *sk, unsigned char *data, u16 len)
328 {
329 struct mgmt_mode *cp;
330 struct hci_dev *hdev;
331 u16 dev_id;
332 int ret, up;
333
334 cp = (void *) data;
335 dev_id = get_unaligned_le16(&cp->index);
336
337 BT_DBG("request for hci%u", dev_id);
338
339 hdev = hci_dev_get(dev_id);
340 if (!hdev)
341 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
342
343 hci_dev_lock_bh(hdev);
344
345 up = test_bit(HCI_UP, &hdev->flags);
346 if ((cp->val && up) || (!cp->val && !up)) {
347 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
348 goto failed;
349 }
350
351 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
352 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
353 goto failed;
354 }
355
356 ret = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
357 if (ret < 0)
358 goto failed;
359
360 if (cp->val)
361 queue_work(hdev->workqueue, &hdev->power_on);
362 else
363 queue_work(hdev->workqueue, &hdev->power_off);
364
365 ret = 0;
366
367 failed:
368 hci_dev_unlock_bh(hdev);
369 hci_dev_put(hdev);
370 return ret;
371 }
372
373 static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
374 {
375 struct mgmt_mode *cp;
376 struct hci_dev *hdev;
377 u16 dev_id;
378 u8 scan;
379 int err;
380
381 cp = (void *) data;
382 dev_id = get_unaligned_le16(&cp->index);
383
384 BT_DBG("request for hci%u", dev_id);
385
386 hdev = hci_dev_get(dev_id);
387 if (!hdev)
388 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
389
390 hci_dev_lock_bh(hdev);
391
392 if (!test_bit(HCI_UP, &hdev->flags)) {
393 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
394 goto failed;
395 }
396
397 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
398 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
399 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
400 goto failed;
401 }
402
403 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
404 test_bit(HCI_PSCAN, &hdev->flags)) {
405 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
406 goto failed;
407 }
408
409 err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
410 if (err < 0)
411 goto failed;
412
413 scan = SCAN_PAGE;
414
415 if (cp->val)
416 scan |= SCAN_INQUIRY;
417
418 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
419 if (err < 0)
420 mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
421
422 failed:
423 hci_dev_unlock_bh(hdev);
424 hci_dev_put(hdev);
425
426 return err;
427 }
428
429 static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
430 {
431 struct mgmt_mode *cp;
432 struct hci_dev *hdev;
433 u16 dev_id;
434 u8 scan;
435 int err;
436
437 cp = (void *) data;
438 dev_id = get_unaligned_le16(&cp->index);
439
440 BT_DBG("request for hci%u", dev_id);
441
442 hdev = hci_dev_get(dev_id);
443 if (!hdev)
444 return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
445
446 hci_dev_lock_bh(hdev);
447
448 if (!test_bit(HCI_UP, &hdev->flags)) {
449 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
450 goto failed;
451 }
452
453 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
454 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
455 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
456 goto failed;
457 }
458
459 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
460 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
461 goto failed;
462 }
463
464 err = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
465 if (err < 0)
466 goto failed;
467
468 if (cp->val)
469 scan = SCAN_PAGE;
470 else
471 scan = 0;
472
473 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
474 if (err < 0)
475 mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
476
477 failed:
478 hci_dev_unlock_bh(hdev);
479 hci_dev_put(hdev);
480
481 return err;
482 }
483
484 static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
485 {
486 struct sk_buff *skb;
487 struct mgmt_hdr *hdr;
488
489 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
490 if (!skb)
491 return -ENOMEM;
492
493 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
494
495 hdr = (void *) skb_put(skb, sizeof(*hdr));
496 hdr->opcode = cpu_to_le16(event);
497 hdr->len = cpu_to_le16(data_len);
498
499 memcpy(skb_put(skb, data_len), data, data_len);
500
501 hci_send_to_sock(NULL, skb, skip_sk);
502 kfree_skb(skb);
503
504 return 0;
505 }
506
507 static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
508 {
509 struct mgmt_hdr *hdr;
510 struct mgmt_ev_cmd_complete *ev;
511 struct mgmt_mode *rp;
512 struct sk_buff *skb;
513
514 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
515 if (!skb)
516 return -ENOMEM;
517
518 hdr = (void *) skb_put(skb, sizeof(*hdr));
519 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
520 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
521
522 ev = (void *) skb_put(skb, sizeof(*ev));
523 put_unaligned_le16(opcode, &ev->opcode);
524
525 rp = (void *) skb_put(skb, sizeof(*rp));
526 put_unaligned_le16(index, &rp->index);
527 rp->val = val;
528
529 if (sock_queue_rcv_skb(sk, skb) < 0)
530 kfree_skb(skb);
531
532 return 0;
533 }
534
535 static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
536 {
537 struct mgmt_mode *cp, ev;
538 struct hci_dev *hdev;
539 u16 dev_id;
540 int err;
541
542 cp = (void *) data;
543 dev_id = get_unaligned_le16(&cp->index);
544
545 BT_DBG("request for hci%u", dev_id);
546
547 hdev = hci_dev_get(dev_id);
548 if (!hdev)
549 return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
550
551 hci_dev_lock_bh(hdev);
552
553 if (cp->val)
554 set_bit(HCI_PAIRABLE, &hdev->flags);
555 else
556 clear_bit(HCI_PAIRABLE, &hdev->flags);
557
558 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
559 if (err < 0)
560 goto failed;
561
562 put_unaligned_le16(dev_id, &ev.index);
563 ev.val = cp->val;
564
565 err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
566
567 failed:
568 hci_dev_unlock_bh(hdev);
569 hci_dev_put(hdev);
570
571 return err;
572 }
573
574 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
575 {
576 unsigned char *buf;
577 struct mgmt_hdr *hdr;
578 u16 opcode, len;
579 int err;
580
581 BT_DBG("got %zu bytes", msglen);
582
583 if (msglen < sizeof(*hdr))
584 return -EINVAL;
585
586 buf = kmalloc(msglen, GFP_ATOMIC);
587 if (!buf)
588 return -ENOMEM;
589
590 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
591 err = -EFAULT;
592 goto done;
593 }
594
595 hdr = (struct mgmt_hdr *) buf;
596 opcode = get_unaligned_le16(&hdr->opcode);
597 len = get_unaligned_le16(&hdr->len);
598
599 if (len != msglen - sizeof(*hdr)) {
600 err = -EINVAL;
601 goto done;
602 }
603
604 switch (opcode) {
605 case MGMT_OP_READ_VERSION:
606 err = read_version(sk);
607 break;
608 case MGMT_OP_READ_INDEX_LIST:
609 err = read_index_list(sk);
610 break;
611 case MGMT_OP_READ_INFO:
612 err = read_controller_info(sk, buf + sizeof(*hdr), len);
613 break;
614 case MGMT_OP_SET_POWERED:
615 err = set_powered(sk, buf + sizeof(*hdr), len);
616 break;
617 case MGMT_OP_SET_DISCOVERABLE:
618 err = set_discoverable(sk, buf + sizeof(*hdr), len);
619 break;
620 case MGMT_OP_SET_CONNECTABLE:
621 err = set_connectable(sk, buf + sizeof(*hdr), len);
622 break;
623 case MGMT_OP_SET_PAIRABLE:
624 err = set_pairable(sk, buf + sizeof(*hdr), len);
625 break;
626 default:
627 BT_DBG("Unknown op %u", opcode);
628 err = cmd_status(sk, opcode, 0x01);
629 break;
630 }
631
632 if (err < 0)
633 goto done;
634
635 err = msglen;
636
637 done:
638 kfree(buf);
639 return err;
640 }
641
642 int mgmt_index_added(u16 index)
643 {
644 struct mgmt_ev_index_added ev;
645
646 put_unaligned_le16(index, &ev.index);
647
648 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
649 }
650
651 int mgmt_index_removed(u16 index)
652 {
653 struct mgmt_ev_index_added ev;
654
655 put_unaligned_le16(index, &ev.index);
656
657 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
658 }
659
660 struct cmd_lookup {
661 u8 val;
662 struct sock *sk;
663 };
664
665 static void mode_rsp(struct pending_cmd *cmd, void *data)
666 {
667 struct mgmt_mode *cp = cmd->cmd;
668 struct cmd_lookup *match = data;
669
670 if (cp->val != match->val)
671 return;
672
673 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
674
675 list_del(&cmd->list);
676
677 if (match->sk == NULL) {
678 match->sk = cmd->sk;
679 sock_hold(match->sk);
680 }
681
682 mgmt_pending_free(cmd);
683 }
684
685 int mgmt_powered(u16 index, u8 powered)
686 {
687 struct mgmt_mode ev;
688 struct cmd_lookup match = { powered, NULL };
689 int ret;
690
691 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
692
693 put_unaligned_le16(index, &ev.index);
694 ev.val = powered;
695
696 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
697
698 if (match.sk)
699 sock_put(match.sk);
700
701 return ret;
702 }
703
704 int mgmt_discoverable(u16 index, u8 discoverable)
705 {
706 struct mgmt_mode ev;
707 struct cmd_lookup match = { discoverable, NULL };
708 int ret;
709
710 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
711 mode_rsp, &match);
712
713 put_unaligned_le16(index, &ev.index);
714 ev.val = discoverable;
715
716 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
717
718 if (match.sk)
719 sock_put(match.sk);
720
721 return ret;
722 }
723
724 int mgmt_connectable(u16 index, u8 connectable)
725 {
726 struct mgmt_mode ev;
727 struct cmd_lookup match = { connectable, NULL };
728 int ret;
729
730 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
731
732 put_unaligned_le16(index, &ev.index);
733 ev.val = connectable;
734
735 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
736
737 if (match.sk)
738 sock_put(match.sk);
739
740 return ret;
741 }
This page took 0.045396 seconds and 4 git commands to generate.