blob: f5ef7a3374c78491705bc784126a55689a0ae4be [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
41};
42
43LIST_HEAD(cmd_list);
44
Johan Hedbergf7b64e62010-12-13 21:07:06 +020045static int cmd_status(struct sock *sk, u16 cmd, u8 status)
46{
47 struct sk_buff *skb;
48 struct mgmt_hdr *hdr;
49 struct mgmt_ev_cmd_status *ev;
50
51 BT_DBG("sock %p", sk);
52
53 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
54 if (!skb)
55 return -ENOMEM;
56
57 hdr = (void *) skb_put(skb, sizeof(*hdr));
58
59 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
60 hdr->len = cpu_to_le16(sizeof(*ev));
61
62 ev = (void *) skb_put(skb, sizeof(*ev));
63 ev->status = status;
64 put_unaligned_le16(cmd, &ev->opcode);
65
66 if (sock_queue_rcv_skb(sk, skb) < 0)
67 kfree_skb(skb);
68
69 return 0;
70}
71
Johan Hedberga38528f2011-01-22 06:46:43 +020072static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020073{
74 struct sk_buff *skb;
75 struct mgmt_hdr *hdr;
76 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020077
78 BT_DBG("sock %p", sk);
79
Johan Hedberga38528f2011-01-22 06:46:43 +020080 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020081 if (!skb)
82 return -ENOMEM;
83
84 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020085
Johan Hedberg02d98122010-12-13 21:07:04 +020086 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Johan Hedberga38528f2011-01-22 06:46:43 +020087 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020088
Johan Hedberga38528f2011-01-22 06:46:43 +020089 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
90 put_unaligned_le16(cmd, &ev->opcode);
91 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020092
93 if (sock_queue_rcv_skb(sk, skb) < 0)
94 kfree_skb(skb);
95
96 return 0;
97}
98
Johan Hedberga38528f2011-01-22 06:46:43 +020099static int read_version(struct sock *sk)
100{
101 struct mgmt_rp_read_version rp;
102
103 BT_DBG("sock %p", sk);
104
105 rp.version = MGMT_VERSION;
106 put_unaligned_le16(MGMT_REVISION, &rp.revision);
107
108 return cmd_complete(sk, MGMT_OP_READ_VERSION, &rp, sizeof(rp));
109}
110
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200111static int read_index_list(struct sock *sk)
112{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200113 struct mgmt_rp_read_index_list *rp;
114 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200115 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200116 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200117 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200118
119 BT_DBG("sock %p", sk);
120
121 read_lock(&hci_dev_list_lock);
122
123 count = 0;
124 list_for_each(p, &hci_dev_list) {
125 count++;
126 }
127
Johan Hedberga38528f2011-01-22 06:46:43 +0200128 rp_len = sizeof(*rp) + (2 * count);
129 rp = kmalloc(rp_len, GFP_ATOMIC);
130 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100131 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100133 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135 put_unaligned_le16(count, &rp->num_controllers);
136
137 i = 0;
138 list_for_each(p, &hci_dev_list) {
139 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200140
141 hci_del_off_timer(d);
142
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200143 set_bit(HCI_MGMT, &d->flags);
144
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200145 if (test_bit(HCI_SETUP, &d->flags))
146 continue;
147
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148 put_unaligned_le16(d->id, &rp->index[i++]);
149 BT_DBG("Added hci%u", d->id);
150 }
151
152 read_unlock(&hci_dev_list_lock);
153
Johan Hedberga38528f2011-01-22 06:46:43 +0200154 err = cmd_complete(sk, MGMT_OP_READ_INDEX_LIST, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200155
Johan Hedberga38528f2011-01-22 06:46:43 +0200156 kfree(rp);
157
158 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200159}
160
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200161static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200162{
Johan Hedberga38528f2011-01-22 06:46:43 +0200163 struct mgmt_rp_read_info rp;
164 struct mgmt_cp_read_info *cp = (void *) data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200165 struct hci_dev *hdev;
166 u16 dev_id;
Johan Hedberg03811012010-12-08 00:21:06 +0200167
168 BT_DBG("sock %p", sk);
169
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200170 if (len != 2)
171 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
172
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200173 dev_id = get_unaligned_le16(&cp->index);
174
175 BT_DBG("request for hci%u", dev_id);
176
177 hdev = hci_dev_get(dev_id);
Johan Hedberga38528f2011-01-22 06:46:43 +0200178 if (!hdev)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200179 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200180
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200181 hci_del_off_timer(hdev);
182
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200183 hci_dev_lock_bh(hdev);
184
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200185 set_bit(HCI_MGMT, &hdev->flags);
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187 put_unaligned_le16(hdev->id, &rp.index);
188 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200189
Johan Hedberga38528f2011-01-22 06:46:43 +0200190 rp.powered = test_bit(HCI_UP, &hdev->flags);
191 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
192 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
193 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200194
195 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 bacpy(&rp.bdaddr, &hdev->bdaddr);
203 memcpy(rp.features, hdev->features, 8);
204 memcpy(rp.dev_class, hdev->dev_class, 3);
205 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
206 rp.hci_ver = hdev->hci_ver;
207 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
209 hci_dev_unlock_bh(hdev);
210 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200211
Johan Hedberga38528f2011-01-22 06:46:43 +0200212 return cmd_complete(sk, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200213}
214
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200215static void mgmt_pending_free(struct pending_cmd *cmd)
216{
217 sock_put(cmd->sk);
218 kfree(cmd->cmd);
219 kfree(cmd);
220}
221
222static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
223 void *data, u16 len)
224{
225 struct pending_cmd *cmd;
226
227 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
228 if (!cmd)
229 return -ENOMEM;
230
231 cmd->opcode = opcode;
232 cmd->index = index;
233
234 cmd->cmd = kmalloc(len, GFP_ATOMIC);
235 if (!cmd->cmd) {
236 kfree(cmd);
237 return -ENOMEM;
238 }
239
240 memcpy(cmd->cmd, data, len);
241
242 cmd->sk = sk;
243 sock_hold(sk);
244
245 list_add(&cmd->list, &cmd_list);
246
247 return 0;
248}
249
250static void mgmt_pending_foreach(u16 opcode, int index,
251 void (*cb)(struct pending_cmd *cmd, void *data),
252 void *data)
253{
254 struct list_head *p, *n;
255
256 list_for_each_safe(p, n, &cmd_list) {
257 struct pending_cmd *cmd;
258
259 cmd = list_entry(p, struct pending_cmd, list);
260
261 if (cmd->opcode != opcode)
262 continue;
263
264 if (index >= 0 && cmd->index != index)
265 continue;
266
267 cb(cmd, data);
268 }
269}
270
271static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
272{
273 struct list_head *p;
274
275 list_for_each(p, &cmd_list) {
276 struct pending_cmd *cmd;
277
278 cmd = list_entry(p, struct pending_cmd, list);
279
280 if (cmd->opcode != opcode)
281 continue;
282
283 if (index >= 0 && cmd->index != index)
284 continue;
285
286 return cmd;
287 }
288
289 return NULL;
290}
291
Johan Hedberg73f22f62010-12-29 16:00:25 +0200292static void mgmt_pending_remove(u16 opcode, int index)
293{
294 struct pending_cmd *cmd;
295
296 cmd = mgmt_pending_find(opcode, index);
297 if (cmd == NULL)
298 return;
299
300 list_del(&cmd->list);
301 mgmt_pending_free(cmd);
302}
303
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304static int set_powered(struct sock *sk, unsigned char *data, u16 len)
305{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200306 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200307 struct hci_dev *hdev;
308 u16 dev_id;
309 int ret, up;
310
311 cp = (void *) data;
312 dev_id = get_unaligned_le16(&cp->index);
313
314 BT_DBG("request for hci%u", dev_id);
315
316 hdev = hci_dev_get(dev_id);
317 if (!hdev)
318 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
319
320 hci_dev_lock_bh(hdev);
321
322 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200323 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
325 goto failed;
326 }
327
328 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
329 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
330 goto failed;
331 }
332
333 ret = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
334 if (ret < 0)
335 goto failed;
336
Johan Hedberg72a734e2010-12-30 00:38:22 +0200337 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 queue_work(hdev->workqueue, &hdev->power_on);
339 else
340 queue_work(hdev->workqueue, &hdev->power_off);
341
342 ret = 0;
343
344failed:
345 hci_dev_unlock_bh(hdev);
346 hci_dev_put(hdev);
347 return ret;
348}
349
Johan Hedberg73f22f62010-12-29 16:00:25 +0200350static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
351{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200352 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353 struct hci_dev *hdev;
354 u16 dev_id;
355 u8 scan;
356 int err;
357
358 cp = (void *) data;
359 dev_id = get_unaligned_le16(&cp->index);
360
361 BT_DBG("request for hci%u", dev_id);
362
363 hdev = hci_dev_get(dev_id);
364 if (!hdev)
365 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
366
367 hci_dev_lock_bh(hdev);
368
369 if (!test_bit(HCI_UP, &hdev->flags)) {
370 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
371 goto failed;
372 }
373
374 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200375 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
377 goto failed;
378 }
379
Johan Hedberg72a734e2010-12-30 00:38:22 +0200380 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 test_bit(HCI_PSCAN, &hdev->flags)) {
382 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
383 goto failed;
384 }
385
386 err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
387 if (err < 0)
388 goto failed;
389
390 scan = SCAN_PAGE;
391
Johan Hedberg72a734e2010-12-30 00:38:22 +0200392 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 scan |= SCAN_INQUIRY;
394
395 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
396 if (err < 0)
397 mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
398
399failed:
400 hci_dev_unlock_bh(hdev);
401 hci_dev_put(hdev);
402
403 return err;
404}
405
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200406static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
407{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200408 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200409 struct hci_dev *hdev;
410 u16 dev_id;
411 u8 scan;
412 int err;
413
414 cp = (void *) data;
415 dev_id = get_unaligned_le16(&cp->index);
416
417 BT_DBG("request for hci%u", dev_id);
418
419 hdev = hci_dev_get(dev_id);
420 if (!hdev)
421 return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
422
423 hci_dev_lock_bh(hdev);
424
425 if (!test_bit(HCI_UP, &hdev->flags)) {
426 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
427 goto failed;
428 }
429
430 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
431 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
432 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
433 goto failed;
434 }
435
Johan Hedberg72a734e2010-12-30 00:38:22 +0200436 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
438 goto failed;
439 }
440
441 err = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
442 if (err < 0)
443 goto failed;
444
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 scan = SCAN_PAGE;
447 else
448 scan = 0;
449
450 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
451 if (err < 0)
452 mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
453
454failed:
455 hci_dev_unlock_bh(hdev);
456 hci_dev_put(hdev);
457
458 return err;
459}
460
Johan Hedbergc542a062011-01-26 13:11:03 +0200461static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
462{
463 struct sk_buff *skb;
464 struct mgmt_hdr *hdr;
465
466 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
467 if (!skb)
468 return -ENOMEM;
469
470 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
471
472 hdr = (void *) skb_put(skb, sizeof(*hdr));
473 hdr->opcode = cpu_to_le16(event);
474 hdr->len = cpu_to_le16(data_len);
475
476 memcpy(skb_put(skb, data_len), data, data_len);
477
478 hci_send_to_sock(NULL, skb, skip_sk);
479 kfree_skb(skb);
480
481 return 0;
482}
483
Johan Hedberg053f0212011-01-26 13:07:10 +0200484static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
485{
Johan Hedberga38528f2011-01-22 06:46:43 +0200486 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200487
Johan Hedberga38528f2011-01-22 06:46:43 +0200488 put_unaligned_le16(index, &rp.index);
489 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200490
Johan Hedberga38528f2011-01-22 06:46:43 +0200491 return cmd_complete(sk, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200492}
493
Johan Hedbergc542a062011-01-26 13:11:03 +0200494static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
495{
496 struct mgmt_mode *cp, ev;
497 struct hci_dev *hdev;
498 u16 dev_id;
499 int err;
500
501 cp = (void *) data;
502 dev_id = get_unaligned_le16(&cp->index);
503
504 BT_DBG("request for hci%u", dev_id);
505
506 hdev = hci_dev_get(dev_id);
507 if (!hdev)
508 return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
509
510 hci_dev_lock_bh(hdev);
511
512 if (cp->val)
513 set_bit(HCI_PAIRABLE, &hdev->flags);
514 else
515 clear_bit(HCI_PAIRABLE, &hdev->flags);
516
517 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
518 if (err < 0)
519 goto failed;
520
521 put_unaligned_le16(dev_id, &ev.index);
522 ev.val = cp->val;
523
524 err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
525
526failed:
527 hci_dev_unlock_bh(hdev);
528 hci_dev_put(hdev);
529
530 return err;
531}
532
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200533static u8 get_service_classes(struct hci_dev *hdev)
534{
535 struct list_head *p;
536 u8 val = 0;
537
538 list_for_each(p, &hdev->uuids) {
539 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
540
541 val |= uuid->svc_hint;
542 }
543
544 return val;
545}
546
547static int update_class(struct hci_dev *hdev)
548{
549 u8 cod[3];
550
551 BT_DBG("%s", hdev->name);
552
553 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
554 return 0;
555
556 cod[0] = hdev->minor_class;
557 cod[1] = hdev->major_class;
558 cod[2] = get_service_classes(hdev);
559
560 if (memcmp(cod, hdev->dev_class, 3) == 0)
561 return 0;
562
563 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
564}
565
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200566static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
567{
568 struct mgmt_cp_add_uuid *cp;
569 struct hci_dev *hdev;
570 struct bt_uuid *uuid;
571 u16 dev_id;
572 int err;
573
574 cp = (void *) data;
575 dev_id = get_unaligned_le16(&cp->index);
576
577 BT_DBG("request for hci%u", dev_id);
578
579 hdev = hci_dev_get(dev_id);
580 if (!hdev)
581 return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
582
583 hci_dev_lock_bh(hdev);
584
585 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
586 if (!uuid) {
587 err = -ENOMEM;
588 goto failed;
589 }
590
591 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200592 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200593
594 list_add(&uuid->list, &hdev->uuids);
595
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200596 err = update_class(hdev);
597 if (err < 0)
598 goto failed;
599
Johan Hedberga38528f2011-01-22 06:46:43 +0200600 err = cmd_complete(sk, MGMT_OP_ADD_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200601
602failed:
603 hci_dev_unlock_bh(hdev);
604 hci_dev_put(hdev);
605
606 return err;
607}
608
609static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
610{
611 struct list_head *p, *n;
612 struct mgmt_cp_add_uuid *cp;
613 struct hci_dev *hdev;
614 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
615 u16 dev_id;
616 int err, found;
617
618 cp = (void *) data;
619 dev_id = get_unaligned_le16(&cp->index);
620
621 BT_DBG("request for hci%u", dev_id);
622
623 hdev = hci_dev_get(dev_id);
624 if (!hdev)
625 return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
626
627 hci_dev_lock_bh(hdev);
628
629 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
630 err = hci_uuids_clear(hdev);
631 goto unlock;
632 }
633
634 found = 0;
635
636 list_for_each_safe(p, n, &hdev->uuids) {
637 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
638
639 if (memcmp(match->uuid, cp->uuid, 16) != 0)
640 continue;
641
642 list_del(&match->list);
643 found++;
644 }
645
646 if (found == 0) {
647 err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
648 goto unlock;
649 }
650
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651 err = update_class(hdev);
652 if (err < 0)
653 goto unlock;
654
Johan Hedberga38528f2011-01-22 06:46:43 +0200655 err = cmd_complete(sk, MGMT_OP_REMOVE_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200656
657unlock:
658 hci_dev_unlock_bh(hdev);
659 hci_dev_put(hdev);
660
661 return err;
662}
663
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200664static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
665{
666 struct hci_dev *hdev;
667 struct mgmt_cp_set_dev_class *cp;
668 u16 dev_id;
669 int err;
670
671 cp = (void *) data;
672 dev_id = get_unaligned_le16(&cp->index);
673
674 BT_DBG("request for hci%u", dev_id);
675
676 hdev = hci_dev_get(dev_id);
677 if (!hdev)
678 return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
679
680 hci_dev_lock_bh(hdev);
681
682 hdev->major_class = cp->major;
683 hdev->minor_class = cp->minor;
684
685 err = update_class(hdev);
686
687 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200688 err = cmd_complete(sk, MGMT_OP_SET_DEV_CLASS, &dev_id,
689 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690
691 hci_dev_unlock_bh(hdev);
692 hci_dev_put(hdev);
693
694 return err;
695}
696
697static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
698{
699 struct hci_dev *hdev;
700 struct mgmt_cp_set_service_cache *cp;
701 u16 dev_id;
702 int err;
703
704 cp = (void *) data;
705 dev_id = get_unaligned_le16(&cp->index);
706
707 hdev = hci_dev_get(dev_id);
708 if (!hdev)
709 return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
710
711 hci_dev_lock_bh(hdev);
712
713 BT_DBG("hci%u enable %d", dev_id, cp->enable);
714
715 if (cp->enable) {
716 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
717 err = 0;
718 } else {
719 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
720 err = update_class(hdev);
721 }
722
723 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200724 err = cmd_complete(sk, MGMT_OP_SET_SERVICE_CACHE, &dev_id,
725 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200726
727 hci_dev_unlock_bh(hdev);
728 hci_dev_put(hdev);
729
730 return err;
731}
732
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200733static int load_keys(struct sock *sk, unsigned char *data, u16 len)
734{
735 struct hci_dev *hdev;
736 struct mgmt_cp_load_keys *cp;
737 u16 dev_id, key_count, expected_len;
738 int i;
739
740 cp = (void *) data;
741 dev_id = get_unaligned_le16(&cp->index);
742 key_count = get_unaligned_le16(&cp->key_count);
743
744 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
745 if (expected_len != len) {
746 BT_ERR("load_keys: expected %u bytes, got %u bytes",
747 len, expected_len);
748 return -EINVAL;
749 }
750
751 hdev = hci_dev_get(dev_id);
752 if (!hdev)
753 return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
754
755 BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
756 key_count);
757
758 hci_dev_lock_bh(hdev);
759
760 hci_link_keys_clear(hdev);
761
762 set_bit(HCI_LINK_KEYS, &hdev->flags);
763
764 if (cp->debug_keys)
765 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
766 else
767 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
768
769 for (i = 0; i < key_count; i++) {
770 struct mgmt_key_info *key = &cp->keys[i];
771
772 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
773 key->pin_len);
774 }
775
776 hci_dev_unlock_bh(hdev);
777 hci_dev_put(hdev);
778
779 return 0;
780}
781
782static int remove_key(struct sock *sk, unsigned char *data, u16 len)
783{
784 struct hci_dev *hdev;
785 struct mgmt_cp_remove_key *cp;
786 struct hci_conn *conn;
787 u16 dev_id;
788 int err;
789
790 cp = (void *) data;
791 dev_id = get_unaligned_le16(&cp->index);
792
793 hdev = hci_dev_get(dev_id);
794 if (!hdev)
795 return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
796
797 hci_dev_lock_bh(hdev);
798
799 err = hci_remove_link_key(hdev, &cp->bdaddr);
800 if (err < 0) {
801 err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
802 goto unlock;
803 }
804
805 err = 0;
806
807 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
808 goto unlock;
809
810 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
811 if (conn) {
812 struct hci_cp_disconnect dc;
813
814 put_unaligned_le16(conn->handle, &dc.handle);
815 dc.reason = 0x13; /* Remote User Terminated Connection */
816 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
817 }
818
819unlock:
820 hci_dev_unlock_bh(hdev);
821 hci_dev_put(hdev);
822
823 return err;
824}
825
Johan Hedberg8962ee72011-01-20 12:40:27 +0200826static int disconnect(struct sock *sk, unsigned char *data, u16 len)
827{
828 struct hci_dev *hdev;
829 struct mgmt_cp_disconnect *cp;
830 struct hci_cp_disconnect dc;
831 struct hci_conn *conn;
832 u16 dev_id;
833 int err;
834
835 BT_DBG("");
836
837 cp = (void *) data;
838 dev_id = get_unaligned_le16(&cp->index);
839
840 hdev = hci_dev_get(dev_id);
841 if (!hdev)
842 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
843
844 hci_dev_lock_bh(hdev);
845
846 if (!test_bit(HCI_UP, &hdev->flags)) {
847 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
848 goto failed;
849 }
850
851 if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
852 err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
853 goto failed;
854 }
855
856 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
857 if (!conn) {
858 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
859 goto failed;
860 }
861
862 err = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, dev_id, data, len);
863 if (err < 0)
864 goto failed;
865
866 put_unaligned_le16(conn->handle, &dc.handle);
867 dc.reason = 0x13; /* Remote User Terminated Connection */
868
869 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
870 if (err < 0)
871 mgmt_pending_remove(MGMT_OP_DISCONNECT, dev_id);
872
873failed:
874 hci_dev_unlock_bh(hdev);
875 hci_dev_put(hdev);
876
877 return err;
878}
879
Johan Hedberg2784eb42011-01-21 13:56:35 +0200880static int get_connections(struct sock *sk, unsigned char *data, u16 len)
881{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200882 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200883 struct mgmt_rp_get_connections *rp;
884 struct hci_dev *hdev;
885 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200886 size_t rp_len;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200887 u16 dev_id, count;
888 int i, err;
889
890 BT_DBG("");
891
892 cp = (void *) data;
893 dev_id = get_unaligned_le16(&cp->index);
894
895 hdev = hci_dev_get(dev_id);
896 if (!hdev)
897 return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
898
899 hci_dev_lock_bh(hdev);
900
901 count = 0;
902 list_for_each(p, &hdev->conn_hash.list) {
903 count++;
904 }
905
Johan Hedberga38528f2011-01-22 06:46:43 +0200906 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
907 rp = kmalloc(rp_len, GFP_ATOMIC);
908 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200909 err = -ENOMEM;
910 goto unlock;
911 }
912
Johan Hedberg2784eb42011-01-21 13:56:35 +0200913 put_unaligned_le16(dev_id, &rp->index);
914 put_unaligned_le16(count, &rp->conn_count);
915
916 read_lock(&hci_dev_list_lock);
917
918 i = 0;
919 list_for_each(p, &hdev->conn_hash.list) {
920 struct hci_conn *c = list_entry(p, struct hci_conn, list);
921
922 bacpy(&rp->conn[i++], &c->dst);
923 }
924
925 read_unlock(&hci_dev_list_lock);
926
Johan Hedberga38528f2011-01-22 06:46:43 +0200927 err = cmd_complete(sk, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200928
929unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200930 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200931 hci_dev_unlock_bh(hdev);
932 hci_dev_put(hdev);
933 return err;
934}
935
Johan Hedberg980e1a52011-01-22 06:10:07 +0200936static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
937{
938 struct hci_dev *hdev;
939 struct mgmt_cp_pin_code_reply *cp;
940 struct hci_cp_pin_code_reply reply;
941 u16 dev_id;
942 int err;
943
944 BT_DBG("");
945
946 cp = (void *) data;
947 dev_id = get_unaligned_le16(&cp->index);
948
949 hdev = hci_dev_get(dev_id);
950 if (!hdev)
951 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
952
953 hci_dev_lock_bh(hdev);
954
955 if (!test_bit(HCI_UP, &hdev->flags)) {
956 err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
957 goto failed;
958 }
959
960 err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
961 if (err < 0)
962 goto failed;
963
964 bacpy(&reply.bdaddr, &cp->bdaddr);
965 reply.pin_len = cp->pin_len;
966 memcpy(reply.pin_code, cp->pin_code, 16);
967
968 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
969 if (err < 0)
970 mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
971
972failed:
973 hci_dev_unlock_bh(hdev);
974 hci_dev_put(hdev);
975
976 return err;
977}
978
979static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
980{
981 struct hci_dev *hdev;
982 struct mgmt_cp_pin_code_neg_reply *cp;
983 u16 dev_id;
984 int err;
985
986 BT_DBG("");
987
988 cp = (void *) data;
989 dev_id = get_unaligned_le16(&cp->index);
990
991 hdev = hci_dev_get(dev_id);
992 if (!hdev)
993 return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
994
995 hci_dev_lock_bh(hdev);
996
997 if (!test_bit(HCI_UP, &hdev->flags)) {
998 err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
999 goto failed;
1000 }
1001
1002 err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
1003 data, len);
1004 if (err < 0)
1005 goto failed;
1006
1007 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1008 &cp->bdaddr);
1009 if (err < 0)
1010 mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
1011
1012failed:
1013 hci_dev_unlock_bh(hdev);
1014 hci_dev_put(hdev);
1015
1016 return err;
1017}
1018
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001019static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
1020{
1021 struct hci_dev *hdev;
1022 struct mgmt_cp_set_io_capability *cp;
1023 u16 dev_id;
1024
1025 BT_DBG("");
1026
1027 cp = (void *) data;
1028 dev_id = get_unaligned_le16(&cp->index);
1029
1030 hdev = hci_dev_get(dev_id);
1031 if (!hdev)
1032 return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
1033
1034 hci_dev_lock_bh(hdev);
1035
1036 hdev->io_capability = cp->io_capability;
1037
1038 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1039 hdev->io_capability);
1040
1041 hci_dev_unlock_bh(hdev);
1042 hci_dev_put(hdev);
1043
1044 return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY,
1045 &dev_id, sizeof(dev_id));
1046}
1047
Johan Hedberg03811012010-12-08 00:21:06 +02001048int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1049{
1050 unsigned char *buf;
1051 struct mgmt_hdr *hdr;
1052 u16 opcode, len;
1053 int err;
1054
1055 BT_DBG("got %zu bytes", msglen);
1056
1057 if (msglen < sizeof(*hdr))
1058 return -EINVAL;
1059
1060 buf = kmalloc(msglen, GFP_ATOMIC);
1061 if (!buf)
1062 return -ENOMEM;
1063
1064 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1065 err = -EFAULT;
1066 goto done;
1067 }
1068
1069 hdr = (struct mgmt_hdr *) buf;
1070 opcode = get_unaligned_le16(&hdr->opcode);
1071 len = get_unaligned_le16(&hdr->len);
1072
1073 if (len != msglen - sizeof(*hdr)) {
1074 err = -EINVAL;
1075 goto done;
1076 }
1077
1078 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001079 case MGMT_OP_READ_VERSION:
1080 err = read_version(sk);
1081 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001082 case MGMT_OP_READ_INDEX_LIST:
1083 err = read_index_list(sk);
1084 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001085 case MGMT_OP_READ_INFO:
1086 err = read_controller_info(sk, buf + sizeof(*hdr), len);
1087 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001088 case MGMT_OP_SET_POWERED:
1089 err = set_powered(sk, buf + sizeof(*hdr), len);
1090 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001091 case MGMT_OP_SET_DISCOVERABLE:
1092 err = set_discoverable(sk, buf + sizeof(*hdr), len);
1093 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001094 case MGMT_OP_SET_CONNECTABLE:
1095 err = set_connectable(sk, buf + sizeof(*hdr), len);
1096 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001097 case MGMT_OP_SET_PAIRABLE:
1098 err = set_pairable(sk, buf + sizeof(*hdr), len);
1099 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001100 case MGMT_OP_ADD_UUID:
1101 err = add_uuid(sk, buf + sizeof(*hdr), len);
1102 break;
1103 case MGMT_OP_REMOVE_UUID:
1104 err = remove_uuid(sk, buf + sizeof(*hdr), len);
1105 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001106 case MGMT_OP_SET_DEV_CLASS:
1107 err = set_dev_class(sk, buf + sizeof(*hdr), len);
1108 break;
1109 case MGMT_OP_SET_SERVICE_CACHE:
1110 err = set_service_cache(sk, buf + sizeof(*hdr), len);
1111 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001112 case MGMT_OP_LOAD_KEYS:
1113 err = load_keys(sk, buf + sizeof(*hdr), len);
1114 break;
1115 case MGMT_OP_REMOVE_KEY:
1116 err = remove_key(sk, buf + sizeof(*hdr), len);
1117 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001118 case MGMT_OP_DISCONNECT:
1119 err = disconnect(sk, buf + sizeof(*hdr), len);
1120 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001121 case MGMT_OP_GET_CONNECTIONS:
1122 err = get_connections(sk, buf + sizeof(*hdr), len);
1123 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001124 case MGMT_OP_PIN_CODE_REPLY:
1125 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1126 break;
1127 case MGMT_OP_PIN_CODE_NEG_REPLY:
1128 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1129 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001130 case MGMT_OP_SET_IO_CAPABILITY:
1131 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1132 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001133 default:
1134 BT_DBG("Unknown op %u", opcode);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001135 err = cmd_status(sk, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001136 break;
1137 }
1138
Johan Hedberge41d8b42010-12-13 21:07:03 +02001139 if (err < 0)
1140 goto done;
1141
Johan Hedberg03811012010-12-08 00:21:06 +02001142 err = msglen;
1143
1144done:
1145 kfree(buf);
1146 return err;
1147}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001148
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001149int mgmt_index_added(u16 index)
1150{
1151 struct mgmt_ev_index_added ev;
1152
1153 put_unaligned_le16(index, &ev.index);
1154
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001155 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001156}
1157
1158int mgmt_index_removed(u16 index)
1159{
1160 struct mgmt_ev_index_added ev;
1161
1162 put_unaligned_le16(index, &ev.index);
1163
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
1165}
1166
Johan Hedberg73f22f62010-12-29 16:00:25 +02001167struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001168 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169 struct sock *sk;
1170};
1171
Johan Hedberg72a734e2010-12-30 00:38:22 +02001172static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001173{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001174 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001175 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001176
Johan Hedberg72a734e2010-12-30 00:38:22 +02001177 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178 return;
1179
Johan Hedberg053f0212011-01-26 13:07:10 +02001180 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181
1182 list_del(&cmd->list);
1183
1184 if (match->sk == NULL) {
1185 match->sk = cmd->sk;
1186 sock_hold(match->sk);
1187 }
1188
1189 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001190}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001191
1192int mgmt_powered(u16 index, u8 powered)
1193{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001194 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001195 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001197
Johan Hedberg72a734e2010-12-30 00:38:22 +02001198 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001199
Johan Hedberg72a734e2010-12-30 00:38:22 +02001200 put_unaligned_le16(index, &ev.index);
1201 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
1203 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
1204
1205 if (match.sk)
1206 sock_put(match.sk);
1207
1208 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001209}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001210
Johan Hedberg73f22f62010-12-29 16:00:25 +02001211int mgmt_discoverable(u16 index, u8 discoverable)
1212{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001213 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001214 struct cmd_lookup match = { discoverable, NULL };
1215 int ret;
1216
Johan Hedberg73f22f62010-12-29 16:00:25 +02001217 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001218 mode_rsp, &match);
1219
1220 put_unaligned_le16(index, &ev.index);
1221 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001222
1223 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
1224
1225 if (match.sk)
1226 sock_put(match.sk);
1227
1228 return ret;
1229}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001230
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001231int mgmt_connectable(u16 index, u8 connectable)
1232{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001233 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001234 struct cmd_lookup match = { connectable, NULL };
1235 int ret;
1236
Johan Hedberg72a734e2010-12-30 00:38:22 +02001237 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001238
Johan Hedberg72a734e2010-12-30 00:38:22 +02001239 put_unaligned_le16(index, &ev.index);
1240 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001241
1242 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
1243
1244 if (match.sk)
1245 sock_put(match.sk);
1246
1247 return ret;
1248}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001249
1250int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1251{
1252 struct mgmt_ev_new_key ev;
1253
1254 memset(&ev, 0, sizeof(ev));
1255
1256 put_unaligned_le16(index, &ev.index);
1257
1258 bacpy(&ev.key.bdaddr, &key->bdaddr);
1259 ev.key.type = key->type;
1260 memcpy(ev.key.val, key->val, 16);
1261 ev.key.pin_len = key->pin_len;
1262 ev.old_key_type = old_key_type;
1263
1264 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1265}
Johan Hedbergf7520542011-01-20 12:34:39 +02001266
1267int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1268{
1269 struct mgmt_ev_connected ev;
1270
1271 put_unaligned_le16(index, &ev.index);
1272 bacpy(&ev.bdaddr, bdaddr);
1273
1274 return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
1275}
1276
Johan Hedberg8962ee72011-01-20 12:40:27 +02001277static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1278{
1279 struct mgmt_cp_disconnect *cp = cmd->cmd;
1280 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001281 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001282
Johan Hedberga38528f2011-01-22 06:46:43 +02001283 put_unaligned_le16(cmd->index, &rp.index);
1284 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001285
Johan Hedberga38528f2011-01-22 06:46:43 +02001286 cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001287
1288 *sk = cmd->sk;
1289 sock_hold(*sk);
1290
1291 list_del(&cmd->list);
1292 mgmt_pending_free(cmd);
1293}
1294
Johan Hedbergf7520542011-01-20 12:34:39 +02001295int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1296{
1297 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001298 struct sock *sk = NULL;
1299 int err;
1300
1301 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001302
1303 put_unaligned_le16(index, &ev.index);
1304 bacpy(&ev.bdaddr, bdaddr);
1305
Johan Hedberg8962ee72011-01-20 12:40:27 +02001306 err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
1307
1308 if (sk)
1309 sock_put(sk);
1310
1311 return err;
1312}
1313
1314int mgmt_disconnect_failed(u16 index)
1315{
1316 struct pending_cmd *cmd;
1317 int err;
1318
1319 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1320 if (!cmd)
1321 return -ENOENT;
1322
1323 err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
1324
1325 list_del(&cmd->list);
1326 mgmt_pending_free(cmd);
1327
1328 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001329}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001330
1331int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1332{
1333 struct mgmt_ev_connect_failed ev;
1334
1335 put_unaligned_le16(index, &ev.index);
1336 bacpy(&ev.bdaddr, bdaddr);
1337 ev.status = status;
1338
1339 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1340}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341
1342int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1343{
1344 struct mgmt_ev_pin_code_request ev;
1345
1346 put_unaligned_le16(index, &ev.index);
1347 bacpy(&ev.bdaddr, bdaddr);
1348
1349 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1350}
1351
1352int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1353{
1354 struct pending_cmd *cmd;
1355 int err;
1356
1357 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1358 if (!cmd)
1359 return -ENOENT;
1360
1361 if (status != 0)
1362 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
1363 else
1364 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
1365 bdaddr, sizeof(*bdaddr));
1366
1367 list_del(&cmd->list);
1368 mgmt_pending_free(cmd);
1369
1370 return err;
1371}
1372
1373int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1374{
1375 struct pending_cmd *cmd;
1376 int err;
1377
1378 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1379 if (!cmd)
1380 return -ENOENT;
1381
1382 if (status != 0)
1383 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
1384 else
1385 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1386 bdaddr, sizeof(*bdaddr));
1387
1388 list_del(&cmd->list);
1389 mgmt_pending_free(cmd);
1390
1391 return err;
1392}