blob: 4543ede4ddf3dcd9d539163f3b5442ee01cbe149 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
44LIST_HEAD(cmd_list);
45
Johan Hedbergf7b64e62010-12-13 21:07:06 +020046static int cmd_status(struct sock *sk, u16 cmd, u8 status)
47{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
52 BT_DBG("sock %p", sk);
53
54 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
55 if (!skb)
56 return -ENOMEM;
57
58 hdr = (void *) skb_put(skb, sizeof(*hdr));
59
60 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
61 hdr->len = cpu_to_le16(sizeof(*ev));
62
63 ev = (void *) skb_put(skb, sizeof(*ev));
64 ev->status = status;
65 put_unaligned_le16(cmd, &ev->opcode);
66
67 if (sock_queue_rcv_skb(sk, skb) < 0)
68 kfree_skb(skb);
69
70 return 0;
71}
72
Johan Hedberga38528f2011-01-22 06:46:43 +020073static int cmd_complete(struct sock *sk, u16 cmd, void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020074{
75 struct sk_buff *skb;
76 struct mgmt_hdr *hdr;
77 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020078
79 BT_DBG("sock %p", sk);
80
Johan Hedberga38528f2011-01-22 06:46:43 +020081 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020082 if (!skb)
83 return -ENOMEM;
84
85 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020086
Johan Hedberg02d98122010-12-13 21:07:04 +020087 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Johan Hedberga38528f2011-01-22 06:46:43 +020088 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020089
Johan Hedberga38528f2011-01-22 06:46:43 +020090 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
91 put_unaligned_le16(cmd, &ev->opcode);
92 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020093
94 if (sock_queue_rcv_skb(sk, skb) < 0)
95 kfree_skb(skb);
96
97 return 0;
98}
99
Johan Hedberga38528f2011-01-22 06:46:43 +0200100static int read_version(struct sock *sk)
101{
102 struct mgmt_rp_read_version rp;
103
104 BT_DBG("sock %p", sk);
105
106 rp.version = MGMT_VERSION;
107 put_unaligned_le16(MGMT_REVISION, &rp.revision);
108
109 return cmd_complete(sk, MGMT_OP_READ_VERSION, &rp, sizeof(rp));
110}
111
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200112static int read_index_list(struct sock *sk)
113{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200114 struct mgmt_rp_read_index_list *rp;
115 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200116 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200117 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200118 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200119
120 BT_DBG("sock %p", sk);
121
122 read_lock(&hci_dev_list_lock);
123
124 count = 0;
125 list_for_each(p, &hci_dev_list) {
126 count++;
127 }
128
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 rp_len = sizeof(*rp) + (2 * count);
130 rp = kmalloc(rp_len, GFP_ATOMIC);
131 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100132 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200133 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100134 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200136 put_unaligned_le16(count, &rp->num_controllers);
137
138 i = 0;
139 list_for_each(p, &hci_dev_list) {
140 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200141
142 hci_del_off_timer(d);
143
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200144 set_bit(HCI_MGMT, &d->flags);
145
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200146 if (test_bit(HCI_SETUP, &d->flags))
147 continue;
148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(d->id, &rp->index[i++]);
150 BT_DBG("Added hci%u", d->id);
151 }
152
153 read_unlock(&hci_dev_list_lock);
154
Johan Hedberga38528f2011-01-22 06:46:43 +0200155 err = cmd_complete(sk, MGMT_OP_READ_INDEX_LIST, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156
Johan Hedberga38528f2011-01-22 06:46:43 +0200157 kfree(rp);
158
159 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160}
161
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200162static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200163{
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 struct mgmt_rp_read_info rp;
165 struct mgmt_cp_read_info *cp = (void *) data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200166 struct hci_dev *hdev;
167 u16 dev_id;
Johan Hedberg03811012010-12-08 00:21:06 +0200168
169 BT_DBG("sock %p", sk);
170
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200171 if (len != 2)
172 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
173
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200174 dev_id = get_unaligned_le16(&cp->index);
175
176 BT_DBG("request for hci%u", dev_id);
177
178 hdev = hci_dev_get(dev_id);
Johan Hedberga38528f2011-01-22 06:46:43 +0200179 if (!hdev)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200180 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200181
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200182 hci_del_off_timer(hdev);
183
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200184 hci_dev_lock_bh(hdev);
185
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200186 set_bit(HCI_MGMT, &hdev->flags);
187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 put_unaligned_le16(hdev->id, &rp.index);
189 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.powered = test_bit(HCI_UP, &hdev->flags);
192 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
193 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
194 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200195
196 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200197 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 bacpy(&rp.bdaddr, &hdev->bdaddr);
204 memcpy(rp.features, hdev->features, 8);
205 memcpy(rp.dev_class, hdev->dev_class, 3);
206 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
207 rp.hci_ver = hdev->hci_ver;
208 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200209
210 hci_dev_unlock_bh(hdev);
211 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200212
Johan Hedberga38528f2011-01-22 06:46:43 +0200213 return cmd_complete(sk, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200214}
215
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200216static void mgmt_pending_free(struct pending_cmd *cmd)
217{
218 sock_put(cmd->sk);
219 kfree(cmd->cmd);
220 kfree(cmd);
221}
222
Johan Hedberg366a0332011-02-19 12:05:55 -0300223static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
224 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200225{
226 struct pending_cmd *cmd;
227
228 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
229 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300230 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200231
232 cmd->opcode = opcode;
233 cmd->index = index;
234
235 cmd->cmd = kmalloc(len, GFP_ATOMIC);
236 if (!cmd->cmd) {
237 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300238 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 }
240
241 memcpy(cmd->cmd, data, len);
242
243 cmd->sk = sk;
244 sock_hold(sk);
245
246 list_add(&cmd->list, &cmd_list);
247
Johan Hedberg366a0332011-02-19 12:05:55 -0300248 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200249}
250
251static void mgmt_pending_foreach(u16 opcode, int index,
252 void (*cb)(struct pending_cmd *cmd, void *data),
253 void *data)
254{
255 struct list_head *p, *n;
256
257 list_for_each_safe(p, n, &cmd_list) {
258 struct pending_cmd *cmd;
259
260 cmd = list_entry(p, struct pending_cmd, list);
261
262 if (cmd->opcode != opcode)
263 continue;
264
265 if (index >= 0 && cmd->index != index)
266 continue;
267
268 cb(cmd, data);
269 }
270}
271
272static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
273{
274 struct list_head *p;
275
276 list_for_each(p, &cmd_list) {
277 struct pending_cmd *cmd;
278
279 cmd = list_entry(p, struct pending_cmd, list);
280
281 if (cmd->opcode != opcode)
282 continue;
283
284 if (index >= 0 && cmd->index != index)
285 continue;
286
287 return cmd;
288 }
289
290 return NULL;
291}
292
Johan Hedberga664b5b2011-02-19 12:06:02 -0300293static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200294{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200295 list_del(&cmd->list);
296 mgmt_pending_free(cmd);
297}
298
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299static int set_powered(struct sock *sk, unsigned char *data, u16 len)
300{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200301 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300303 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 u16 dev_id;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
307 cp = (void *) data;
308 dev_id = get_unaligned_le16(&cp->index);
309
310 BT_DBG("request for hci%u", dev_id);
311
312 hdev = hci_dev_get(dev_id);
313 if (!hdev)
314 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
315
316 hci_dev_lock_bh(hdev);
317
318 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200319 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300320 err = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321 goto failed;
322 }
323
324 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
Johan Hedberg366a0332011-02-19 12:05:55 -0300325 err = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200326 goto failed;
327 }
328
Johan Hedberg366a0332011-02-19 12:05:55 -0300329 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
330 if (!cmd) {
331 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334
Johan Hedberg72a734e2010-12-30 00:38:22 +0200335 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 queue_work(hdev->workqueue, &hdev->power_on);
337 else
338 queue_work(hdev->workqueue, &hdev->power_off);
339
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341
342failed:
343 hci_dev_unlock_bh(hdev);
344 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300345 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346}
347
Johan Hedberg73f22f62010-12-29 16:00:25 +0200348static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
349{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200350 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200351 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300352 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353 u16 dev_id;
354 u8 scan;
355 int err;
356
357 cp = (void *) data;
358 dev_id = get_unaligned_le16(&cp->index);
359
360 BT_DBG("request for hci%u", dev_id);
361
362 hdev = hci_dev_get(dev_id);
363 if (!hdev)
364 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
365
366 hci_dev_lock_bh(hdev);
367
368 if (!test_bit(HCI_UP, &hdev->flags)) {
369 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
370 goto failed;
371 }
372
373 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200374 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
Johan Hedberg73f22f62010-12-29 16:00:25 +0200375 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
376 goto failed;
377 }
378
Johan Hedberg72a734e2010-12-30 00:38:22 +0200379 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 test_bit(HCI_PSCAN, &hdev->flags)) {
381 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
382 goto failed;
383 }
384
Johan Hedberg366a0332011-02-19 12:05:55 -0300385 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
386 if (!cmd) {
387 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300389 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200390
391 scan = SCAN_PAGE;
392
Johan Hedberg72a734e2010-12-30 00:38:22 +0200393 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 scan |= SCAN_INQUIRY;
395
396 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
397 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300398 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399
400failed:
401 hci_dev_unlock_bh(hdev);
402 hci_dev_put(hdev);
403
404 return err;
405}
406
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200407static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
408{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200409 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200410 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300411 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200412 u16 dev_id;
413 u8 scan;
414 int err;
415
416 cp = (void *) data;
417 dev_id = get_unaligned_le16(&cp->index);
418
419 BT_DBG("request for hci%u", dev_id);
420
421 hdev = hci_dev_get(dev_id);
422 if (!hdev)
423 return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
424
425 hci_dev_lock_bh(hdev);
426
427 if (!test_bit(HCI_UP, &hdev->flags)) {
428 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
429 goto failed;
430 }
431
432 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
433 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
434 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
435 goto failed;
436 }
437
Johan Hedberg72a734e2010-12-30 00:38:22 +0200438 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439 err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
440 goto failed;
441 }
442
Johan Hedberg366a0332011-02-19 12:05:55 -0300443 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
444 if (!cmd) {
445 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300447 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448
Johan Hedberg72a734e2010-12-30 00:38:22 +0200449 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 scan = SCAN_PAGE;
451 else
452 scan = 0;
453
454 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
455 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300456 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457
458failed:
459 hci_dev_unlock_bh(hdev);
460 hci_dev_put(hdev);
461
462 return err;
463}
464
Johan Hedbergc542a062011-01-26 13:11:03 +0200465static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
466{
467 struct sk_buff *skb;
468 struct mgmt_hdr *hdr;
469
470 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
471 if (!skb)
472 return -ENOMEM;
473
474 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
475
476 hdr = (void *) skb_put(skb, sizeof(*hdr));
477 hdr->opcode = cpu_to_le16(event);
478 hdr->len = cpu_to_le16(data_len);
479
480 memcpy(skb_put(skb, data_len), data, data_len);
481
482 hci_send_to_sock(NULL, skb, skip_sk);
483 kfree_skb(skb);
484
485 return 0;
486}
487
Johan Hedberg053f0212011-01-26 13:07:10 +0200488static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
489{
Johan Hedberga38528f2011-01-22 06:46:43 +0200490 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200491
Johan Hedberga38528f2011-01-22 06:46:43 +0200492 put_unaligned_le16(index, &rp.index);
493 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200494
Johan Hedberga38528f2011-01-22 06:46:43 +0200495 return cmd_complete(sk, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200496}
497
Johan Hedbergc542a062011-01-26 13:11:03 +0200498static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
499{
500 struct mgmt_mode *cp, ev;
501 struct hci_dev *hdev;
502 u16 dev_id;
503 int err;
504
505 cp = (void *) data;
506 dev_id = get_unaligned_le16(&cp->index);
507
508 BT_DBG("request for hci%u", dev_id);
509
510 hdev = hci_dev_get(dev_id);
511 if (!hdev)
512 return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
513
514 hci_dev_lock_bh(hdev);
515
516 if (cp->val)
517 set_bit(HCI_PAIRABLE, &hdev->flags);
518 else
519 clear_bit(HCI_PAIRABLE, &hdev->flags);
520
521 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
522 if (err < 0)
523 goto failed;
524
525 put_unaligned_le16(dev_id, &ev.index);
526 ev.val = cp->val;
527
528 err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
529
530failed:
531 hci_dev_unlock_bh(hdev);
532 hci_dev_put(hdev);
533
534 return err;
535}
536
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200537static u8 get_service_classes(struct hci_dev *hdev)
538{
539 struct list_head *p;
540 u8 val = 0;
541
542 list_for_each(p, &hdev->uuids) {
543 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
544
545 val |= uuid->svc_hint;
546 }
547
548 return val;
549}
550
551static int update_class(struct hci_dev *hdev)
552{
553 u8 cod[3];
554
555 BT_DBG("%s", hdev->name);
556
557 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
558 return 0;
559
560 cod[0] = hdev->minor_class;
561 cod[1] = hdev->major_class;
562 cod[2] = get_service_classes(hdev);
563
564 if (memcmp(cod, hdev->dev_class, 3) == 0)
565 return 0;
566
567 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
568}
569
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200570static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
571{
572 struct mgmt_cp_add_uuid *cp;
573 struct hci_dev *hdev;
574 struct bt_uuid *uuid;
575 u16 dev_id;
576 int err;
577
578 cp = (void *) data;
579 dev_id = get_unaligned_le16(&cp->index);
580
581 BT_DBG("request for hci%u", dev_id);
582
583 hdev = hci_dev_get(dev_id);
584 if (!hdev)
585 return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
586
587 hci_dev_lock_bh(hdev);
588
589 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
590 if (!uuid) {
591 err = -ENOMEM;
592 goto failed;
593 }
594
595 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200596 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200597
598 list_add(&uuid->list, &hdev->uuids);
599
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600 err = update_class(hdev);
601 if (err < 0)
602 goto failed;
603
Johan Hedberga38528f2011-01-22 06:46:43 +0200604 err = cmd_complete(sk, MGMT_OP_ADD_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200605
606failed:
607 hci_dev_unlock_bh(hdev);
608 hci_dev_put(hdev);
609
610 return err;
611}
612
613static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
614{
615 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100616 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200617 struct hci_dev *hdev;
618 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
619 u16 dev_id;
620 int err, found;
621
622 cp = (void *) data;
623 dev_id = get_unaligned_le16(&cp->index);
624
625 BT_DBG("request for hci%u", dev_id);
626
627 hdev = hci_dev_get(dev_id);
628 if (!hdev)
629 return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
630
631 hci_dev_lock_bh(hdev);
632
633 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
634 err = hci_uuids_clear(hdev);
635 goto unlock;
636 }
637
638 found = 0;
639
640 list_for_each_safe(p, n, &hdev->uuids) {
641 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
642
643 if (memcmp(match->uuid, cp->uuid, 16) != 0)
644 continue;
645
646 list_del(&match->list);
647 found++;
648 }
649
650 if (found == 0) {
651 err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
652 goto unlock;
653 }
654
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200655 err = update_class(hdev);
656 if (err < 0)
657 goto unlock;
658
Johan Hedberga38528f2011-01-22 06:46:43 +0200659 err = cmd_complete(sk, MGMT_OP_REMOVE_UUID, &dev_id, sizeof(dev_id));
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200660
661unlock:
662 hci_dev_unlock_bh(hdev);
663 hci_dev_put(hdev);
664
665 return err;
666}
667
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200668static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
669{
670 struct hci_dev *hdev;
671 struct mgmt_cp_set_dev_class *cp;
672 u16 dev_id;
673 int err;
674
675 cp = (void *) data;
676 dev_id = get_unaligned_le16(&cp->index);
677
678 BT_DBG("request for hci%u", dev_id);
679
680 hdev = hci_dev_get(dev_id);
681 if (!hdev)
682 return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
683
684 hci_dev_lock_bh(hdev);
685
686 hdev->major_class = cp->major;
687 hdev->minor_class = cp->minor;
688
689 err = update_class(hdev);
690
691 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200692 err = cmd_complete(sk, MGMT_OP_SET_DEV_CLASS, &dev_id,
693 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200694
695 hci_dev_unlock_bh(hdev);
696 hci_dev_put(hdev);
697
698 return err;
699}
700
701static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
702{
703 struct hci_dev *hdev;
704 struct mgmt_cp_set_service_cache *cp;
705 u16 dev_id;
706 int err;
707
708 cp = (void *) data;
709 dev_id = get_unaligned_le16(&cp->index);
710
711 hdev = hci_dev_get(dev_id);
712 if (!hdev)
713 return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
714
715 hci_dev_lock_bh(hdev);
716
717 BT_DBG("hci%u enable %d", dev_id, cp->enable);
718
719 if (cp->enable) {
720 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
721 err = 0;
722 } else {
723 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
724 err = update_class(hdev);
725 }
726
727 if (err == 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200728 err = cmd_complete(sk, MGMT_OP_SET_SERVICE_CACHE, &dev_id,
729 sizeof(dev_id));
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200730
731 hci_dev_unlock_bh(hdev);
732 hci_dev_put(hdev);
733
734 return err;
735}
736
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200737static int load_keys(struct sock *sk, unsigned char *data, u16 len)
738{
739 struct hci_dev *hdev;
740 struct mgmt_cp_load_keys *cp;
741 u16 dev_id, key_count, expected_len;
742 int i;
743
744 cp = (void *) data;
745 dev_id = get_unaligned_le16(&cp->index);
746 key_count = get_unaligned_le16(&cp->key_count);
747
748 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
749 if (expected_len != len) {
750 BT_ERR("load_keys: expected %u bytes, got %u bytes",
751 len, expected_len);
752 return -EINVAL;
753 }
754
755 hdev = hci_dev_get(dev_id);
756 if (!hdev)
757 return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
758
759 BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
760 key_count);
761
762 hci_dev_lock_bh(hdev);
763
764 hci_link_keys_clear(hdev);
765
766 set_bit(HCI_LINK_KEYS, &hdev->flags);
767
768 if (cp->debug_keys)
769 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
770 else
771 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
772
773 for (i = 0; i < key_count; i++) {
774 struct mgmt_key_info *key = &cp->keys[i];
775
776 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
777 key->pin_len);
778 }
779
780 hci_dev_unlock_bh(hdev);
781 hci_dev_put(hdev);
782
783 return 0;
784}
785
786static int remove_key(struct sock *sk, unsigned char *data, u16 len)
787{
788 struct hci_dev *hdev;
789 struct mgmt_cp_remove_key *cp;
790 struct hci_conn *conn;
791 u16 dev_id;
792 int err;
793
794 cp = (void *) data;
795 dev_id = get_unaligned_le16(&cp->index);
796
797 hdev = hci_dev_get(dev_id);
798 if (!hdev)
799 return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
800
801 hci_dev_lock_bh(hdev);
802
803 err = hci_remove_link_key(hdev, &cp->bdaddr);
804 if (err < 0) {
805 err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
806 goto unlock;
807 }
808
809 err = 0;
810
811 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
812 goto unlock;
813
814 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
815 if (conn) {
816 struct hci_cp_disconnect dc;
817
818 put_unaligned_le16(conn->handle, &dc.handle);
819 dc.reason = 0x13; /* Remote User Terminated Connection */
820 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
821 }
822
823unlock:
824 hci_dev_unlock_bh(hdev);
825 hci_dev_put(hdev);
826
827 return err;
828}
829
Johan Hedberg8962ee72011-01-20 12:40:27 +0200830static int disconnect(struct sock *sk, unsigned char *data, u16 len)
831{
832 struct hci_dev *hdev;
833 struct mgmt_cp_disconnect *cp;
834 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300835 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200836 struct hci_conn *conn;
837 u16 dev_id;
838 int err;
839
840 BT_DBG("");
841
842 cp = (void *) data;
843 dev_id = get_unaligned_le16(&cp->index);
844
845 hdev = hci_dev_get(dev_id);
846 if (!hdev)
847 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
848
849 hci_dev_lock_bh(hdev);
850
851 if (!test_bit(HCI_UP, &hdev->flags)) {
852 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
853 goto failed;
854 }
855
856 if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
857 err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
858 goto failed;
859 }
860
861 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
862 if (!conn) {
863 err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
864 goto failed;
865 }
866
Johan Hedberg366a0332011-02-19 12:05:55 -0300867 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, dev_id, data, len);
868 if (!cmd) {
869 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200870 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300871 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200872
873 put_unaligned_le16(conn->handle, &dc.handle);
874 dc.reason = 0x13; /* Remote User Terminated Connection */
875
876 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
877 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300878 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200879
880failed:
881 hci_dev_unlock_bh(hdev);
882 hci_dev_put(hdev);
883
884 return err;
885}
886
Johan Hedberg2784eb42011-01-21 13:56:35 +0200887static int get_connections(struct sock *sk, unsigned char *data, u16 len)
888{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200889 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200890 struct mgmt_rp_get_connections *rp;
891 struct hci_dev *hdev;
892 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200893 size_t rp_len;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200894 u16 dev_id, count;
895 int i, err;
896
897 BT_DBG("");
898
899 cp = (void *) data;
900 dev_id = get_unaligned_le16(&cp->index);
901
902 hdev = hci_dev_get(dev_id);
903 if (!hdev)
904 return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
905
906 hci_dev_lock_bh(hdev);
907
908 count = 0;
909 list_for_each(p, &hdev->conn_hash.list) {
910 count++;
911 }
912
Johan Hedberga38528f2011-01-22 06:46:43 +0200913 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
914 rp = kmalloc(rp_len, GFP_ATOMIC);
915 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200916 err = -ENOMEM;
917 goto unlock;
918 }
919
Johan Hedberg2784eb42011-01-21 13:56:35 +0200920 put_unaligned_le16(dev_id, &rp->index);
921 put_unaligned_le16(count, &rp->conn_count);
922
923 read_lock(&hci_dev_list_lock);
924
925 i = 0;
926 list_for_each(p, &hdev->conn_hash.list) {
927 struct hci_conn *c = list_entry(p, struct hci_conn, list);
928
929 bacpy(&rp->conn[i++], &c->dst);
930 }
931
932 read_unlock(&hci_dev_list_lock);
933
Johan Hedberga38528f2011-01-22 06:46:43 +0200934 err = cmd_complete(sk, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200935
936unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200937 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200938 hci_dev_unlock_bh(hdev);
939 hci_dev_put(hdev);
940 return err;
941}
942
Johan Hedberg980e1a52011-01-22 06:10:07 +0200943static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
944{
945 struct hci_dev *hdev;
946 struct mgmt_cp_pin_code_reply *cp;
947 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300948 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200949 u16 dev_id;
950 int err;
951
952 BT_DBG("");
953
954 cp = (void *) data;
955 dev_id = get_unaligned_le16(&cp->index);
956
957 hdev = hci_dev_get(dev_id);
958 if (!hdev)
Johan Hedberg59a24b52011-02-19 12:05:58 -0300959 return cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200960
961 hci_dev_lock_bh(hdev);
962
963 if (!test_bit(HCI_UP, &hdev->flags)) {
964 err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
965 goto failed;
966 }
967
Johan Hedberg366a0332011-02-19 12:05:55 -0300968 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
969 if (!cmd) {
970 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200971 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300972 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200973
974 bacpy(&reply.bdaddr, &cp->bdaddr);
975 reply.pin_len = cp->pin_len;
976 memcpy(reply.pin_code, cp->pin_code, 16);
977
978 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
979 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300980 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200981
982failed:
983 hci_dev_unlock_bh(hdev);
984 hci_dev_put(hdev);
985
986 return err;
987}
988
989static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
990{
991 struct hci_dev *hdev;
992 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -0300993 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200994 u16 dev_id;
995 int err;
996
997 BT_DBG("");
998
999 cp = (void *) data;
1000 dev_id = get_unaligned_le16(&cp->index);
1001
1002 hdev = hci_dev_get(dev_id);
1003 if (!hdev)
1004 return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
1005
1006 hci_dev_lock_bh(hdev);
1007
1008 if (!test_bit(HCI_UP, &hdev->flags)) {
1009 err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
1010 goto failed;
1011 }
1012
Johan Hedberg366a0332011-02-19 12:05:55 -03001013 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001014 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001015 if (!cmd) {
1016 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001017 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001018 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001019
1020 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1021 &cp->bdaddr);
1022 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001023 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001024
1025failed:
1026 hci_dev_unlock_bh(hdev);
1027 hci_dev_put(hdev);
1028
1029 return err;
1030}
1031
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001032static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
1033{
1034 struct hci_dev *hdev;
1035 struct mgmt_cp_set_io_capability *cp;
1036 u16 dev_id;
1037
1038 BT_DBG("");
1039
1040 cp = (void *) data;
1041 dev_id = get_unaligned_le16(&cp->index);
1042
1043 hdev = hci_dev_get(dev_id);
1044 if (!hdev)
1045 return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
1046
1047 hci_dev_lock_bh(hdev);
1048
1049 hdev->io_capability = cp->io_capability;
1050
1051 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1052 hdev->io_capability);
1053
1054 hci_dev_unlock_bh(hdev);
1055 hci_dev_put(hdev);
1056
1057 return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY,
1058 &dev_id, sizeof(dev_id));
1059}
1060
Johan Hedberge9a416b2011-02-19 12:05:56 -03001061static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1062{
1063 struct hci_dev *hdev = conn->hdev;
1064 struct list_head *p;
1065
1066 list_for_each(p, &cmd_list) {
1067 struct pending_cmd *cmd;
1068
1069 cmd = list_entry(p, struct pending_cmd, list);
1070
1071 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1072 continue;
1073
1074 if (cmd->index != hdev->id)
1075 continue;
1076
1077 if (cmd->user_data != conn)
1078 continue;
1079
1080 return cmd;
1081 }
1082
1083 return NULL;
1084}
1085
1086static void pairing_complete(struct pending_cmd *cmd, u8 status)
1087{
1088 struct mgmt_rp_pair_device rp;
1089 struct hci_conn *conn = cmd->user_data;
1090
1091 rp.index = cmd->index;
1092 bacpy(&rp.bdaddr, &conn->dst);
1093 rp.status = status;
1094
1095 cmd_complete(cmd->sk, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
1096
1097 /* So we don't get further callbacks for this connection */
1098 conn->connect_cfm_cb = NULL;
1099 conn->security_cfm_cb = NULL;
1100 conn->disconn_cfm_cb = NULL;
1101
1102 hci_conn_put(conn);
1103
Johan Hedberga664b5b2011-02-19 12:06:02 -03001104 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001105}
1106
1107static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1108{
1109 struct pending_cmd *cmd;
1110
1111 BT_DBG("status %u", status);
1112
1113 cmd = find_pairing(conn);
1114 if (!cmd) {
1115 BT_DBG("Unable to find a pending command");
1116 return;
1117 }
1118
1119 pairing_complete(cmd, status);
1120}
1121
1122static int pair_device(struct sock *sk, unsigned char *data, u16 len)
1123{
1124 struct hci_dev *hdev;
1125 struct mgmt_cp_pair_device *cp;
1126 struct pending_cmd *cmd;
1127 u8 sec_level, auth_type;
1128 struct hci_conn *conn;
1129 u16 dev_id;
1130 int err;
1131
1132 BT_DBG("");
1133
1134 cp = (void *) data;
1135 dev_id = get_unaligned_le16(&cp->index);
1136
1137 hdev = hci_dev_get(dev_id);
1138 if (!hdev)
1139 return cmd_status(sk, MGMT_OP_PAIR_DEVICE, ENODEV);
1140
1141 hci_dev_lock_bh(hdev);
1142
1143 if (cp->io_cap == 0x03) {
1144 sec_level = BT_SECURITY_MEDIUM;
1145 auth_type = HCI_AT_DEDICATED_BONDING;
1146 } else {
1147 sec_level = BT_SECURITY_HIGH;
1148 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1149 }
1150
1151 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
1152 if (!conn) {
1153 err = -ENOMEM;
1154 goto unlock;
1155 }
1156
1157 if (conn->connect_cfm_cb) {
1158 hci_conn_put(conn);
1159 err = cmd_status(sk, MGMT_OP_PAIR_DEVICE, EBUSY);
1160 goto unlock;
1161 }
1162
1163 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, dev_id, data, len);
1164 if (!cmd) {
1165 err = -ENOMEM;
1166 hci_conn_put(conn);
1167 goto unlock;
1168 }
1169
1170 conn->connect_cfm_cb = pairing_complete_cb;
1171 conn->security_cfm_cb = pairing_complete_cb;
1172 conn->disconn_cfm_cb = pairing_complete_cb;
1173 conn->io_capability = cp->io_cap;
1174 cmd->user_data = conn;
1175
1176 if (conn->state == BT_CONNECTED &&
1177 hci_conn_security(conn, sec_level, auth_type))
1178 pairing_complete(cmd, 0);
1179
1180 err = 0;
1181
1182unlock:
1183 hci_dev_unlock_bh(hdev);
1184 hci_dev_put(hdev);
1185
1186 return err;
1187}
1188
Johan Hedberga5c29682011-02-19 12:05:57 -03001189static int user_confirm_reply(struct sock *sk, unsigned char *data, u16 len,
1190 int success)
1191{
1192 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1193 u16 dev_id, mgmt_op, hci_op;
1194 struct pending_cmd *cmd;
1195 struct hci_dev *hdev;
1196 int err;
1197
1198 BT_DBG("");
1199
1200 dev_id = get_unaligned_le16(&cp->index);
1201
1202 if (success) {
1203 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1204 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1205 } else {
1206 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1207 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1208 }
1209
1210 hdev = hci_dev_get(dev_id);
1211 if (!hdev)
1212 return cmd_status(sk, mgmt_op, ENODEV);
1213
1214 if (!test_bit(HCI_UP, &hdev->flags)) {
1215 err = cmd_status(sk, mgmt_op, ENETDOWN);
1216 goto failed;
1217 }
1218
1219 cmd = mgmt_pending_add(sk, mgmt_op, dev_id, data, len);
1220 if (!cmd) {
1221 err = -ENOMEM;
1222 goto failed;
1223 }
1224
1225 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001226 if (err < 0)
1227 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001228
1229failed:
1230 hci_dev_unlock_bh(hdev);
1231 hci_dev_put(hdev);
1232
1233 return err;
1234}
1235
Johan Hedberg03811012010-12-08 00:21:06 +02001236int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1237{
1238 unsigned char *buf;
1239 struct mgmt_hdr *hdr;
1240 u16 opcode, len;
1241 int err;
1242
1243 BT_DBG("got %zu bytes", msglen);
1244
1245 if (msglen < sizeof(*hdr))
1246 return -EINVAL;
1247
1248 buf = kmalloc(msglen, GFP_ATOMIC);
1249 if (!buf)
1250 return -ENOMEM;
1251
1252 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1253 err = -EFAULT;
1254 goto done;
1255 }
1256
1257 hdr = (struct mgmt_hdr *) buf;
1258 opcode = get_unaligned_le16(&hdr->opcode);
1259 len = get_unaligned_le16(&hdr->len);
1260
1261 if (len != msglen - sizeof(*hdr)) {
1262 err = -EINVAL;
1263 goto done;
1264 }
1265
1266 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001267 case MGMT_OP_READ_VERSION:
1268 err = read_version(sk);
1269 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001270 case MGMT_OP_READ_INDEX_LIST:
1271 err = read_index_list(sk);
1272 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001273 case MGMT_OP_READ_INFO:
1274 err = read_controller_info(sk, buf + sizeof(*hdr), len);
1275 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001276 case MGMT_OP_SET_POWERED:
1277 err = set_powered(sk, buf + sizeof(*hdr), len);
1278 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001279 case MGMT_OP_SET_DISCOVERABLE:
1280 err = set_discoverable(sk, buf + sizeof(*hdr), len);
1281 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001282 case MGMT_OP_SET_CONNECTABLE:
1283 err = set_connectable(sk, buf + sizeof(*hdr), len);
1284 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001285 case MGMT_OP_SET_PAIRABLE:
1286 err = set_pairable(sk, buf + sizeof(*hdr), len);
1287 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001288 case MGMT_OP_ADD_UUID:
1289 err = add_uuid(sk, buf + sizeof(*hdr), len);
1290 break;
1291 case MGMT_OP_REMOVE_UUID:
1292 err = remove_uuid(sk, buf + sizeof(*hdr), len);
1293 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001294 case MGMT_OP_SET_DEV_CLASS:
1295 err = set_dev_class(sk, buf + sizeof(*hdr), len);
1296 break;
1297 case MGMT_OP_SET_SERVICE_CACHE:
1298 err = set_service_cache(sk, buf + sizeof(*hdr), len);
1299 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001300 case MGMT_OP_LOAD_KEYS:
1301 err = load_keys(sk, buf + sizeof(*hdr), len);
1302 break;
1303 case MGMT_OP_REMOVE_KEY:
1304 err = remove_key(sk, buf + sizeof(*hdr), len);
1305 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001306 case MGMT_OP_DISCONNECT:
1307 err = disconnect(sk, buf + sizeof(*hdr), len);
1308 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001309 case MGMT_OP_GET_CONNECTIONS:
1310 err = get_connections(sk, buf + sizeof(*hdr), len);
1311 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001312 case MGMT_OP_PIN_CODE_REPLY:
1313 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1314 break;
1315 case MGMT_OP_PIN_CODE_NEG_REPLY:
1316 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1317 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001318 case MGMT_OP_SET_IO_CAPABILITY:
1319 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1320 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001321 case MGMT_OP_PAIR_DEVICE:
1322 err = pair_device(sk, buf + sizeof(*hdr), len);
1323 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001324 case MGMT_OP_USER_CONFIRM_REPLY:
1325 err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 1);
1326 break;
1327 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
1328 err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 0);
1329 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001330 default:
1331 BT_DBG("Unknown op %u", opcode);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001332 err = cmd_status(sk, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001333 break;
1334 }
1335
Johan Hedberge41d8b42010-12-13 21:07:03 +02001336 if (err < 0)
1337 goto done;
1338
Johan Hedberg03811012010-12-08 00:21:06 +02001339 err = msglen;
1340
1341done:
1342 kfree(buf);
1343 return err;
1344}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001345
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001346int mgmt_index_added(u16 index)
1347{
1348 struct mgmt_ev_index_added ev;
1349
1350 put_unaligned_le16(index, &ev.index);
1351
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001352 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001353}
1354
1355int mgmt_index_removed(u16 index)
1356{
1357 struct mgmt_ev_index_added ev;
1358
1359 put_unaligned_le16(index, &ev.index);
1360
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001361 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
1362}
1363
Johan Hedberg73f22f62010-12-29 16:00:25 +02001364struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001365 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001366 struct sock *sk;
1367};
1368
Johan Hedberg72a734e2010-12-30 00:38:22 +02001369static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001370{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001371 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001372 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001373
Johan Hedberg72a734e2010-12-30 00:38:22 +02001374 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001375 return;
1376
Johan Hedberg053f0212011-01-26 13:07:10 +02001377 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001378
1379 list_del(&cmd->list);
1380
1381 if (match->sk == NULL) {
1382 match->sk = cmd->sk;
1383 sock_hold(match->sk);
1384 }
1385
1386 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001387}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001388
1389int mgmt_powered(u16 index, u8 powered)
1390{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001391 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001392 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001393 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001394
Johan Hedberg72a734e2010-12-30 00:38:22 +02001395 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001396
Johan Hedberg72a734e2010-12-30 00:38:22 +02001397 put_unaligned_le16(index, &ev.index);
1398 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001399
1400 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
1401
1402 if (match.sk)
1403 sock_put(match.sk);
1404
1405 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001406}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001407
Johan Hedberg73f22f62010-12-29 16:00:25 +02001408int mgmt_discoverable(u16 index, u8 discoverable)
1409{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001410 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001411 struct cmd_lookup match = { discoverable, NULL };
1412 int ret;
1413
Johan Hedberg73f22f62010-12-29 16:00:25 +02001414 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001415 mode_rsp, &match);
1416
1417 put_unaligned_le16(index, &ev.index);
1418 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001419
1420 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
1421
1422 if (match.sk)
1423 sock_put(match.sk);
1424
1425 return ret;
1426}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001427
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001428int mgmt_connectable(u16 index, u8 connectable)
1429{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001430 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001431 struct cmd_lookup match = { connectable, NULL };
1432 int ret;
1433
Johan Hedberg72a734e2010-12-30 00:38:22 +02001434 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001435
Johan Hedberg72a734e2010-12-30 00:38:22 +02001436 put_unaligned_le16(index, &ev.index);
1437 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001438
1439 ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
1440
1441 if (match.sk)
1442 sock_put(match.sk);
1443
1444 return ret;
1445}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001446
1447int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1448{
1449 struct mgmt_ev_new_key ev;
1450
1451 memset(&ev, 0, sizeof(ev));
1452
1453 put_unaligned_le16(index, &ev.index);
1454
1455 bacpy(&ev.key.bdaddr, &key->bdaddr);
1456 ev.key.type = key->type;
1457 memcpy(ev.key.val, key->val, 16);
1458 ev.key.pin_len = key->pin_len;
1459 ev.old_key_type = old_key_type;
1460
1461 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1462}
Johan Hedbergf7520542011-01-20 12:34:39 +02001463
1464int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1465{
1466 struct mgmt_ev_connected ev;
1467
1468 put_unaligned_le16(index, &ev.index);
1469 bacpy(&ev.bdaddr, bdaddr);
1470
1471 return mgmt_event(MGMT_EV_CONNECTED, &ev, sizeof(ev), NULL);
1472}
1473
Johan Hedberg8962ee72011-01-20 12:40:27 +02001474static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1475{
1476 struct mgmt_cp_disconnect *cp = cmd->cmd;
1477 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001478 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001479
Johan Hedberga38528f2011-01-22 06:46:43 +02001480 put_unaligned_le16(cmd->index, &rp.index);
1481 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001482
Johan Hedberga38528f2011-01-22 06:46:43 +02001483 cmd_complete(cmd->sk, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001484
1485 *sk = cmd->sk;
1486 sock_hold(*sk);
1487
Johan Hedberga664b5b2011-02-19 12:06:02 -03001488 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489}
1490
Johan Hedbergf7520542011-01-20 12:34:39 +02001491int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1492{
1493 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494 struct sock *sk = NULL;
1495 int err;
1496
1497 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001498
1499 put_unaligned_le16(index, &ev.index);
1500 bacpy(&ev.bdaddr, bdaddr);
1501
Johan Hedberg8962ee72011-01-20 12:40:27 +02001502 err = mgmt_event(MGMT_EV_DISCONNECTED, &ev, sizeof(ev), sk);
1503
1504 if (sk)
1505 sock_put(sk);
1506
1507 return err;
1508}
1509
1510int mgmt_disconnect_failed(u16 index)
1511{
1512 struct pending_cmd *cmd;
1513 int err;
1514
1515 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1516 if (!cmd)
1517 return -ENOENT;
1518
1519 err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
1520
Johan Hedberga664b5b2011-02-19 12:06:02 -03001521 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001522
1523 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001524}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001525
1526int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1527{
1528 struct mgmt_ev_connect_failed ev;
1529
1530 put_unaligned_le16(index, &ev.index);
1531 bacpy(&ev.bdaddr, bdaddr);
1532 ev.status = status;
1533
1534 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1535}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001536
1537int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1538{
1539 struct mgmt_ev_pin_code_request ev;
1540
1541 put_unaligned_le16(index, &ev.index);
1542 bacpy(&ev.bdaddr, bdaddr);
1543
1544 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1545}
1546
1547int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1548{
1549 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001550 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001551 int err;
1552
1553 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1554 if (!cmd)
1555 return -ENOENT;
1556
Johan Hedbergac56fb12011-02-19 12:05:59 -03001557 put_unaligned_le16(index, &rp.index);
1558 bacpy(&rp.bdaddr, bdaddr);
1559 rp.status = status;
1560
1561 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY, &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001562
Johan Hedberga664b5b2011-02-19 12:06:02 -03001563 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001564
1565 return err;
1566}
1567
1568int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1569{
1570 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001571 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001572 int err;
1573
1574 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1575 if (!cmd)
1576 return -ENOENT;
1577
Johan Hedbergac56fb12011-02-19 12:05:59 -03001578 put_unaligned_le16(index, &rp.index);
1579 bacpy(&rp.bdaddr, bdaddr);
1580 rp.status = status;
1581
1582 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1583 &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001584
Johan Hedberga664b5b2011-02-19 12:06:02 -03001585 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001586
1587 return err;
1588}
Johan Hedberga5c29682011-02-19 12:05:57 -03001589
1590int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1591{
1592 struct mgmt_ev_user_confirm_request ev;
1593
1594 BT_DBG("hci%u", index);
1595
1596 put_unaligned_le16(index, &ev.index);
1597 bacpy(&ev.bdaddr, bdaddr);
1598 put_unaligned_le32(value, &ev.value);
1599
1600 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, &ev, sizeof(ev), NULL);
1601}
1602
1603static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1604 u8 opcode)
1605{
1606 struct pending_cmd *cmd;
1607 struct mgmt_rp_user_confirm_reply rp;
1608 int err;
1609
1610 cmd = mgmt_pending_find(opcode, index);
1611 if (!cmd)
1612 return -ENOENT;
1613
1614 put_unaligned_le16(index, &rp.index);
1615 bacpy(&rp.bdaddr, bdaddr);
1616 rp.status = status;
1617 err = cmd_complete(cmd->sk, opcode, &rp, sizeof(rp));
1618
Johan Hedberga664b5b2011-02-19 12:06:02 -03001619 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001620
1621 return err;
1622}
1623
1624int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1625{
1626 return confirm_reply_complete(index, bdaddr, status,
1627 MGMT_OP_USER_CONFIRM_REPLY);
1628}
1629
1630int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1631 u8 status)
1632{
1633 return confirm_reply_complete(index, bdaddr, status,
1634 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1635}
Johan Hedberg2a611692011-02-19 12:06:00 -03001636
1637int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1638{
1639 struct mgmt_ev_auth_failed ev;
1640
1641 put_unaligned_le16(index, &ev.index);
1642 bacpy(&ev.bdaddr, bdaddr);
1643 ev.status = status;
1644
1645 return mgmt_event(MGMT_EV_AUTH_FAILED, &ev, sizeof(ev), NULL);
1646}