blob: 2c76342968660f97a1911783f26d60a7a96b715a [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>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040026#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020036struct pending_cmd {
37 struct list_head list;
38 __u16 opcode;
39 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010040 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030042 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043};
44
Johannes Bergb5ad8b72011-06-01 08:54:45 +020045static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020046
Szymon Janc4e51eae2011-02-25 19:05:48 +010047static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020048{
49 struct sk_buff *skb;
50 struct mgmt_hdr *hdr;
51 struct mgmt_ev_cmd_status *ev;
52
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
69 if (sock_queue_rcv_skb(sk, skb) < 0)
70 kfree_skb(skb);
71
72 return 0;
73}
74
Szymon Janc4e51eae2011-02-25 19:05:48 +010075static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
76 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020077{
78 struct sk_buff *skb;
79 struct mgmt_hdr *hdr;
80 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020081
82 BT_DBG("sock %p", sk);
83
Johan Hedberga38528f2011-01-22 06:46:43 +020084 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020085 if (!skb)
86 return -ENOMEM;
87
88 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020089
Johan Hedberg02d98122010-12-13 21:07:04 +020090 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010091 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020092 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020093
Johan Hedberga38528f2011-01-22 06:46:43 +020094 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
95 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010096
97 if (rp)
98 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020099
100 if (sock_queue_rcv_skb(sk, skb) < 0)
101 kfree_skb(skb);
102
103 return 0;
104}
105
Johan Hedberga38528f2011-01-22 06:46:43 +0200106static int read_version(struct sock *sk)
107{
108 struct mgmt_rp_read_version rp;
109
110 BT_DBG("sock %p", sk);
111
112 rp.version = MGMT_VERSION;
113 put_unaligned_le16(MGMT_REVISION, &rp.revision);
114
Szymon Janc4e51eae2011-02-25 19:05:48 +0100115 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
116 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200117}
118
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200119static int read_index_list(struct sock *sk)
120{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200121 struct mgmt_rp_read_index_list *rp;
122 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200123 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200125 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126
127 BT_DBG("sock %p", sk);
128
129 read_lock(&hci_dev_list_lock);
130
131 count = 0;
132 list_for_each(p, &hci_dev_list) {
133 count++;
134 }
135
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 rp_len = sizeof(*rp) + (2 * count);
137 rp = kmalloc(rp_len, GFP_ATOMIC);
138 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100139 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100141 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200143 put_unaligned_le16(count, &rp->num_controllers);
144
145 i = 0;
146 list_for_each(p, &hci_dev_list) {
147 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200148
149 hci_del_off_timer(d);
150
151 if (test_bit(HCI_SETUP, &d->flags))
152 continue;
153
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200154 put_unaligned_le16(d->id, &rp->index[i++]);
155 BT_DBG("Added hci%u", d->id);
156 }
157
158 read_unlock(&hci_dev_list_lock);
159
Szymon Janc4e51eae2011-02-25 19:05:48 +0100160 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
161 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200162
Johan Hedberga38528f2011-01-22 06:46:43 +0200163 kfree(rp);
164
165 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166}
167
Szymon Janc4e51eae2011-02-25 19:05:48 +0100168static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200169{
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200171 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200172
Szymon Janc4e51eae2011-02-25 19:05:48 +0100173 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200174
Szymon Janc4e51eae2011-02-25 19:05:48 +0100175 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200176 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100177 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200178
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200179 hci_del_off_timer(hdev);
180
Andre Guedes8c156c32011-07-07 10:30:36 -0300181 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200182
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200183 set_bit(HCI_MGMT, &hdev->flags);
184
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200185 memset(&rp, 0, sizeof(rp));
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200188
Johan Hedberga38528f2011-01-22 06:46:43 +0200189 rp.powered = test_bit(HCI_UP, &hdev->flags);
190 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
191 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
192 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193
194 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200195 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200196 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200197 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 bacpy(&rp.bdaddr, &hdev->bdaddr);
202 memcpy(rp.features, hdev->features, 8);
203 memcpy(rp.dev_class, hdev->dev_class, 3);
204 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
205 rp.hci_ver = hdev->hci_ver;
206 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200208 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
209
Andre Guedes8c156c32011-07-07 10:30:36 -0300210 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200212
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 return cmd_complete(sk, index, 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);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100219 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220 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
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100235 cmd->param = kmalloc(len, GFP_ATOMIC);
236 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200237 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300238 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 }
240
Szymon Janc8fce6352011-03-22 13:12:20 +0100241 if (data)
242 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200243
244 cmd->sk = sk;
245 sock_hold(sk);
246
247 list_add(&cmd->list, &cmd_list);
248
Johan Hedberg366a0332011-02-19 12:05:55 -0300249 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200250}
251
252static void mgmt_pending_foreach(u16 opcode, int index,
253 void (*cb)(struct pending_cmd *cmd, void *data),
254 void *data)
255{
256 struct list_head *p, *n;
257
258 list_for_each_safe(p, n, &cmd_list) {
259 struct pending_cmd *cmd;
260
261 cmd = list_entry(p, struct pending_cmd, list);
262
263 if (cmd->opcode != opcode)
264 continue;
265
266 if (index >= 0 && cmd->index != index)
267 continue;
268
269 cb(cmd, data);
270 }
271}
272
273static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
274{
275 struct list_head *p;
276
277 list_for_each(p, &cmd_list) {
278 struct pending_cmd *cmd;
279
280 cmd = list_entry(p, struct pending_cmd, list);
281
282 if (cmd->opcode != opcode)
283 continue;
284
285 if (index >= 0 && cmd->index != index)
286 continue;
287
288 return cmd;
289 }
290
291 return NULL;
292}
293
Johan Hedberga664b5b2011-02-19 12:06:02 -0300294static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200295{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296 list_del(&cmd->list);
297 mgmt_pending_free(cmd);
298}
299
Szymon Janc4e51eae2011-02-25 19:05:48 +0100300static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200302 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300304 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
307 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100311 if (len != sizeof(*cp))
312 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
313
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317
Andre Guedes8c156c32011-07-07 10:30:36 -0300318 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
320 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200321 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200323 goto failed;
324 }
325
Szymon Janc4e51eae2011-02-25 19:05:48 +0100326 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
327 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
329 }
330
Szymon Janc4e51eae2011-02-25 19:05:48 +0100331 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300332 if (!cmd) {
333 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
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
Johan Hedberg366a0332011-02-19 12:05:55 -0300342 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
344failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300345 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300347 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348}
349
Szymon Janc4e51eae2011-02-25 19:05:48 +0100350static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
351 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200353 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300355 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 u8 scan;
357 int err;
358
359 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100363 if (len != sizeof(*cp))
364 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369
Andre Guedes8c156c32011-07-07 10:30:36 -0300370 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
372 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374 goto failed;
375 }
376
Szymon Janc4e51eae2011-02-25 19:05:48 +0100377 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
378 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
379 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 goto failed;
381 }
382
Johan Hedberg72a734e2010-12-30 00:38:22 +0200383 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200384 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100385 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 goto failed;
387 }
388
Szymon Janc4e51eae2011-02-25 19:05:48 +0100389 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300390 if (!cmd) {
391 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200392 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300393 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394
395 scan = SCAN_PAGE;
396
Johan Hedberg72a734e2010-12-30 00:38:22 +0200397 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398 scan |= SCAN_INQUIRY;
399
400 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
401 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300402 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
404failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300405 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200406 hci_dev_put(hdev);
407
408 return err;
409}
410
Szymon Janc4e51eae2011-02-25 19:05:48 +0100411static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
412 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200414 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300416 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417 u8 scan;
418 int err;
419
420 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Janc4e51eae2011-02-25 19:05:48 +0100422 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100424 if (len != sizeof(*cp))
425 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
426
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
Andre Guedes8c156c32011-07-07 10:30:36 -0300431 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200432
433 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 goto failed;
436 }
437
Szymon Janc4e51eae2011-02-25 19:05:48 +0100438 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
439 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
440 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200441 goto failed;
442 }
443
Johan Hedberg72a734e2010-12-30 00:38:22 +0200444 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
447 }
448
Szymon Janc4e51eae2011-02-25 19:05:48 +0100449 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300450 if (!cmd) {
451 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300453 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454
Johan Hedberg72a734e2010-12-30 00:38:22 +0200455 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456 scan = SCAN_PAGE;
457 else
458 scan = 0;
459
460 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
461 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300462 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463
464failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300465 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200466 hci_dev_put(hdev);
467
468 return err;
469}
470
Szymon Janc4e51eae2011-02-25 19:05:48 +0100471static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
472 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200473{
474 struct sk_buff *skb;
475 struct mgmt_hdr *hdr;
476
477 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
478 if (!skb)
479 return -ENOMEM;
480
481 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
482
483 hdr = (void *) skb_put(skb, sizeof(*hdr));
484 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100485 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200486 hdr->len = cpu_to_le16(data_len);
487
Szymon Janc4e51eae2011-02-25 19:05:48 +0100488 if (data)
489 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200490
491 hci_send_to_sock(NULL, skb, skip_sk);
492 kfree_skb(skb);
493
494 return 0;
495}
496
Johan Hedberg053f0212011-01-26 13:07:10 +0200497static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
498{
Johan Hedberga38528f2011-01-22 06:46:43 +0200499 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200500
Johan Hedberga38528f2011-01-22 06:46:43 +0200501 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200502
Szymon Janc4e51eae2011-02-25 19:05:48 +0100503 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200504}
505
Szymon Janc4e51eae2011-02-25 19:05:48 +0100506static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
507 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200508{
509 struct mgmt_mode *cp, ev;
510 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200511 int err;
512
513 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200514
Szymon Janc4e51eae2011-02-25 19:05:48 +0100515 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200516
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100517 if (len != sizeof(*cp))
518 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
Andre Guedes8c156c32011-07-07 10:30:36 -0300524 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200525
526 if (cp->val)
527 set_bit(HCI_PAIRABLE, &hdev->flags);
528 else
529 clear_bit(HCI_PAIRABLE, &hdev->flags);
530
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532 if (err < 0)
533 goto failed;
534
Johan Hedbergc542a062011-01-26 13:11:03 +0200535 ev.val = cp->val;
536
Szymon Janc4e51eae2011-02-25 19:05:48 +0100537 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200538
539failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300540 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200541 hci_dev_put(hdev);
542
543 return err;
544}
545
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546#define EIR_FLAGS 0x01 /* flags */
547#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
548#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
549#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
550#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
551#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
552#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
553#define EIR_NAME_SHORT 0x08 /* shortened local name */
554#define EIR_NAME_COMPLETE 0x09 /* complete local name */
555#define EIR_TX_POWER 0x0A /* transmit power level */
556#define EIR_DEVICE_ID 0x10 /* device ID */
557
558#define PNP_INFO_SVCLASS_ID 0x1200
559
560static u8 bluetooth_base_uuid[] = {
561 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
562 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563};
564
565static u16 get_uuid16(u8 *uuid128)
566{
567 u32 val;
568 int i;
569
570 for (i = 0; i < 12; i++) {
571 if (bluetooth_base_uuid[i] != uuid128[i])
572 return 0;
573 }
574
575 memcpy(&val, &uuid128[12], 4);
576
577 val = le32_to_cpu(val);
578 if (val > 0xffff)
579 return 0;
580
581 return (u16) val;
582}
583
584static void create_eir(struct hci_dev *hdev, u8 *data)
585{
586 u8 *ptr = data;
587 u16 eir_len = 0;
588 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
589 int i, truncated = 0;
590 struct list_head *p;
591 size_t name_len;
592
593 name_len = strlen(hdev->dev_name);
594
595 if (name_len > 0) {
596 /* EIR Data type */
597 if (name_len > 48) {
598 name_len = 48;
599 ptr[1] = EIR_NAME_SHORT;
600 } else
601 ptr[1] = EIR_NAME_COMPLETE;
602
603 /* EIR Data length */
604 ptr[0] = name_len + 1;
605
606 memcpy(ptr + 2, hdev->dev_name, name_len);
607
608 eir_len += (name_len + 2);
609 ptr += (name_len + 2);
610 }
611
612 memset(uuid16_list, 0, sizeof(uuid16_list));
613
614 /* Group all UUID16 types */
615 list_for_each(p, &hdev->uuids) {
616 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
617 u16 uuid16;
618
619 uuid16 = get_uuid16(uuid->uuid);
620 if (uuid16 == 0)
621 return;
622
623 if (uuid16 < 0x1100)
624 continue;
625
626 if (uuid16 == PNP_INFO_SVCLASS_ID)
627 continue;
628
629 /* Stop if not enough space to put next UUID */
630 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
631 truncated = 1;
632 break;
633 }
634
635 /* Check for duplicates */
636 for (i = 0; uuid16_list[i] != 0; i++)
637 if (uuid16_list[i] == uuid16)
638 break;
639
640 if (uuid16_list[i] == 0) {
641 uuid16_list[i] = uuid16;
642 eir_len += sizeof(u16);
643 }
644 }
645
646 if (uuid16_list[0] != 0) {
647 u8 *length = ptr;
648
649 /* EIR Data type */
650 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
651
652 ptr += 2;
653 eir_len += 2;
654
655 for (i = 0; uuid16_list[i] != 0; i++) {
656 *ptr++ = (uuid16_list[i] & 0x00ff);
657 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
658 }
659
660 /* EIR Data length */
661 *length = (i * sizeof(u16)) + 1;
662 }
663}
664
665static int update_eir(struct hci_dev *hdev)
666{
667 struct hci_cp_write_eir cp;
668
669 if (!(hdev->features[6] & LMP_EXT_INQ))
670 return 0;
671
672 if (hdev->ssp_mode == 0)
673 return 0;
674
675 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
676 return 0;
677
678 memset(&cp, 0, sizeof(cp));
679
680 create_eir(hdev, cp.data);
681
682 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
683 return 0;
684
685 memcpy(hdev->eir, cp.data, sizeof(cp.data));
686
687 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
688}
689
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690static u8 get_service_classes(struct hci_dev *hdev)
691{
692 struct list_head *p;
693 u8 val = 0;
694
695 list_for_each(p, &hdev->uuids) {
696 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
697
698 val |= uuid->svc_hint;
699 }
700
701 return val;
702}
703
704static int update_class(struct hci_dev *hdev)
705{
706 u8 cod[3];
707
708 BT_DBG("%s", hdev->name);
709
710 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
711 return 0;
712
713 cod[0] = hdev->minor_class;
714 cod[1] = hdev->major_class;
715 cod[2] = get_service_classes(hdev);
716
717 if (memcmp(cod, hdev->dev_class, 3) == 0)
718 return 0;
719
720 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
721}
722
Szymon Janc4e51eae2011-02-25 19:05:48 +0100723static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200724{
725 struct mgmt_cp_add_uuid *cp;
726 struct hci_dev *hdev;
727 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200728 int err;
729
730 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200731
Szymon Janc4e51eae2011-02-25 19:05:48 +0100732 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200733
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100734 if (len != sizeof(*cp))
735 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
736
Szymon Janc4e51eae2011-02-25 19:05:48 +0100737 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200738 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100739 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200740
Andre Guedes8c156c32011-07-07 10:30:36 -0300741 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200742
743 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
744 if (!uuid) {
745 err = -ENOMEM;
746 goto failed;
747 }
748
749 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200750 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200751
752 list_add(&uuid->list, &hdev->uuids);
753
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200754 err = update_class(hdev);
755 if (err < 0)
756 goto failed;
757
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300758 err = update_eir(hdev);
759 if (err < 0)
760 goto failed;
761
Szymon Janc4e51eae2011-02-25 19:05:48 +0100762 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200763
764failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300765 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200766 hci_dev_put(hdev);
767
768 return err;
769}
770
Szymon Janc4e51eae2011-02-25 19:05:48 +0100771static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200772{
773 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100774 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200775 struct hci_dev *hdev;
776 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777 int err, found;
778
779 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200780
Szymon Janc4e51eae2011-02-25 19:05:48 +0100781 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100783 if (len != sizeof(*cp))
784 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
785
Szymon Janc4e51eae2011-02-25 19:05:48 +0100786 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200787 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100788 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200789
Andre Guedes8c156c32011-07-07 10:30:36 -0300790 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200791
792 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
793 err = hci_uuids_clear(hdev);
794 goto unlock;
795 }
796
797 found = 0;
798
799 list_for_each_safe(p, n, &hdev->uuids) {
800 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
801
802 if (memcmp(match->uuid, cp->uuid, 16) != 0)
803 continue;
804
805 list_del(&match->list);
806 found++;
807 }
808
809 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100810 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200811 goto unlock;
812 }
813
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200814 err = update_class(hdev);
815 if (err < 0)
816 goto unlock;
817
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300818 err = update_eir(hdev);
819 if (err < 0)
820 goto unlock;
821
Szymon Janc4e51eae2011-02-25 19:05:48 +0100822 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200823
824unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300825 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200826 hci_dev_put(hdev);
827
828 return err;
829}
830
Szymon Janc4e51eae2011-02-25 19:05:48 +0100831static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
832 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200833{
834 struct hci_dev *hdev;
835 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200836 int err;
837
838 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200839
Szymon Janc4e51eae2011-02-25 19:05:48 +0100840 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200841
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100842 if (len != sizeof(*cp))
843 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
844
Szymon Janc4e51eae2011-02-25 19:05:48 +0100845 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200846 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100847 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200848
Andre Guedes8c156c32011-07-07 10:30:36 -0300849 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200850
851 hdev->major_class = cp->major;
852 hdev->minor_class = cp->minor;
853
854 err = update_class(hdev);
855
856 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100857 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200858
Andre Guedes8c156c32011-07-07 10:30:36 -0300859 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200860 hci_dev_put(hdev);
861
862 return err;
863}
864
Szymon Janc4e51eae2011-02-25 19:05:48 +0100865static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
866 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867{
868 struct hci_dev *hdev;
869 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870 int err;
871
872 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100874 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100875 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100876
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200880
Andre Guedes8c156c32011-07-07 10:30:36 -0300881 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200882
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200884
885 if (cp->enable) {
886 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
887 err = 0;
888 } else {
889 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
890 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300891 if (err == 0)
892 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200893 }
894
895 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100896 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
897 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898
Andre Guedes8c156c32011-07-07 10:30:36 -0300899 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900 hci_dev_put(hdev);
901
902 return err;
903}
904
Szymon Janc4e51eae2011-02-25 19:05:48 +0100905static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200906{
907 struct hci_dev *hdev;
908 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300910 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200911
912 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100913
914 if (len < sizeof(*cp))
915 return -EINVAL;
916
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200917 key_count = get_unaligned_le16(&cp->key_count);
918
919 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300920 if (expected_len != len) {
921 BT_ERR("load_keys: expected %u bytes, got %u bytes",
922 len, expected_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200923 return -EINVAL;
924 }
925
Szymon Janc4e51eae2011-02-25 19:05:48 +0100926 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200927 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200929
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931 key_count);
932
Andre Guedes8c156c32011-07-07 10:30:36 -0300933 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200934
935 hci_link_keys_clear(hdev);
936
937 set_bit(HCI_LINK_KEYS, &hdev->flags);
938
939 if (cp->debug_keys)
940 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
941 else
942 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
943
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300944 for (i = 0; i < key_count; i++) {
945 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200946
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700947 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200948 key->pin_len);
949 }
950
Andre Guedes8c156c32011-07-07 10:30:36 -0300951 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200952 hci_dev_put(hdev);
953
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300954 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200955}
956
Szymon Janc4e51eae2011-02-25 19:05:48 +0100957static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200958{
959 struct hci_dev *hdev;
960 struct mgmt_cp_remove_key *cp;
961 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200962 int err;
963
964 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200965
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100966 if (len != sizeof(*cp))
967 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
968
Szymon Janc4e51eae2011-02-25 19:05:48 +0100969 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200970 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200972
Andre Guedes8c156c32011-07-07 10:30:36 -0300973 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974
975 err = hci_remove_link_key(hdev, &cp->bdaddr);
976 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978 goto unlock;
979 }
980
981 err = 0;
982
983 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
984 goto unlock;
985
986 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
987 if (conn) {
988 struct hci_cp_disconnect dc;
989
990 put_unaligned_le16(conn->handle, &dc.handle);
991 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400992 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200993 }
994
995unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300996 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200997 hci_dev_put(hdev);
998
999 return err;
1000}
1001
Szymon Janc4e51eae2011-02-25 19:05:48 +01001002static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001003{
1004 struct hci_dev *hdev;
1005 struct mgmt_cp_disconnect *cp;
1006 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001007 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001008 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001009 int err;
1010
1011 BT_DBG("");
1012
1013 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001014
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001015 if (len != sizeof(*cp))
1016 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1017
Szymon Janc4e51eae2011-02-25 19:05:48 +01001018 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001019 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001021
Andre Guedes8c156c32011-07-07 10:30:36 -03001022 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023
1024 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026 goto failed;
1027 }
1028
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1030 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001031 goto failed;
1032 }
1033
1034 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001035 if (!conn)
1036 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1037
Johan Hedberg8962ee72011-01-20 12:40:27 +02001038 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001039 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001040 goto failed;
1041 }
1042
Szymon Janc4e51eae2011-02-25 19:05:48 +01001043 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001044 if (!cmd) {
1045 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001047 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001048
1049 put_unaligned_le16(conn->handle, &dc.handle);
1050 dc.reason = 0x13; /* Remote User Terminated Connection */
1051
1052 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1053 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001054 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001055
1056failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001057 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058 hci_dev_put(hdev);
1059
1060 return err;
1061}
1062
Szymon Janc8ce62842011-03-01 16:55:32 +01001063static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001064{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001065 struct mgmt_rp_get_connections *rp;
1066 struct hci_dev *hdev;
1067 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001068 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001069 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001070 int i, err;
1071
1072 BT_DBG("");
1073
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001075 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077
Andre Guedes8c156c32011-07-07 10:30:36 -03001078 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001079
1080 count = 0;
1081 list_for_each(p, &hdev->conn_hash.list) {
1082 count++;
1083 }
1084
Johan Hedberga38528f2011-01-22 06:46:43 +02001085 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1086 rp = kmalloc(rp_len, GFP_ATOMIC);
1087 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001088 err = -ENOMEM;
1089 goto unlock;
1090 }
1091
Johan Hedberg2784eb42011-01-21 13:56:35 +02001092 put_unaligned_le16(count, &rp->conn_count);
1093
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 i = 0;
1095 list_for_each(p, &hdev->conn_hash.list) {
1096 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1097
1098 bacpy(&rp->conn[i++], &c->dst);
1099 }
1100
Szymon Janc4e51eae2011-02-25 19:05:48 +01001101 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001102
1103unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001104 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001105 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001106 hci_dev_put(hdev);
1107 return err;
1108}
1109
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001110static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1111 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1112{
1113 struct pending_cmd *cmd;
1114 int err;
1115
1116 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1117 sizeof(*cp));
1118 if (!cmd)
1119 return -ENOMEM;
1120
1121 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1122 &cp->bdaddr);
1123 if (err < 0)
1124 mgmt_pending_remove(cmd);
1125
1126 return err;
1127}
1128
Szymon Janc4e51eae2011-02-25 19:05:48 +01001129static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1130 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001131{
1132 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001133 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001134 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001135 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001137 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138 int err;
1139
1140 BT_DBG("");
1141
1142 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001143
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001144 if (len != sizeof(*cp))
1145 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1146
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001148 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150
Andre Guedes8c156c32011-07-07 10:30:36 -03001151 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152
1153 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001155 goto failed;
1156 }
1157
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001158 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1159 if (!conn) {
1160 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1161 goto failed;
1162 }
1163
1164 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1165 bacpy(&ncp.bdaddr, &cp->bdaddr);
1166
1167 BT_ERR("PIN code is not 16 bytes long");
1168
1169 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1170 if (err >= 0)
1171 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1172 EINVAL);
1173
1174 goto failed;
1175 }
1176
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001178 if (!cmd) {
1179 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001180 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001181 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182
1183 bacpy(&reply.bdaddr, &cp->bdaddr);
1184 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001185 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186
1187 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1188 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001189 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001190
1191failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001192 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001193 hci_dev_put(hdev);
1194
1195 return err;
1196}
1197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1199 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200{
1201 struct hci_dev *hdev;
1202 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203 int err;
1204
1205 BT_DBG("");
1206
1207 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001208
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001209 if (len != sizeof(*cp))
1210 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1211 EINVAL);
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001214 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1216 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001217
Andre Guedes8c156c32011-07-07 10:30:36 -03001218 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219
1220 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001221 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1222 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001223 goto failed;
1224 }
1225
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001226 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001227
1228failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001229 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 hci_dev_put(hdev);
1231
1232 return err;
1233}
1234
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1236 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001237{
1238 struct hci_dev *hdev;
1239 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001240
1241 BT_DBG("");
1242
1243 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001244
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001245 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001246 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001247
Szymon Janc4e51eae2011-02-25 19:05:48 +01001248 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001249 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001251
Andre Guedes8c156c32011-07-07 10:30:36 -03001252 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253
1254 hdev->io_capability = cp->io_capability;
1255
1256 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001257 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001258
Andre Guedes8c156c32011-07-07 10:30:36 -03001259 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260 hci_dev_put(hdev);
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001263}
1264
Johan Hedberge9a416b2011-02-19 12:05:56 -03001265static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1266{
1267 struct hci_dev *hdev = conn->hdev;
1268 struct list_head *p;
1269
1270 list_for_each(p, &cmd_list) {
1271 struct pending_cmd *cmd;
1272
1273 cmd = list_entry(p, struct pending_cmd, list);
1274
1275 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1276 continue;
1277
1278 if (cmd->index != hdev->id)
1279 continue;
1280
1281 if (cmd->user_data != conn)
1282 continue;
1283
1284 return cmd;
1285 }
1286
1287 return NULL;
1288}
1289
1290static void pairing_complete(struct pending_cmd *cmd, u8 status)
1291{
1292 struct mgmt_rp_pair_device rp;
1293 struct hci_conn *conn = cmd->user_data;
1294
Johan Hedberge9a416b2011-02-19 12:05:56 -03001295 bacpy(&rp.bdaddr, &conn->dst);
1296 rp.status = status;
1297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001299
1300 /* So we don't get further callbacks for this connection */
1301 conn->connect_cfm_cb = NULL;
1302 conn->security_cfm_cb = NULL;
1303 conn->disconn_cfm_cb = NULL;
1304
1305 hci_conn_put(conn);
1306
Johan Hedberga664b5b2011-02-19 12:06:02 -03001307 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001308}
1309
1310static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1311{
1312 struct pending_cmd *cmd;
1313
1314 BT_DBG("status %u", status);
1315
1316 cmd = find_pairing(conn);
1317 if (!cmd) {
1318 BT_DBG("Unable to find a pending command");
1319 return;
1320 }
1321
1322 pairing_complete(cmd, status);
1323}
1324
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001326{
1327 struct hci_dev *hdev;
1328 struct mgmt_cp_pair_device *cp;
1329 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001330 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331 u8 sec_level, auth_type;
1332 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333 int err;
1334
1335 BT_DBG("");
1336
1337 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001339 if (len != sizeof(*cp))
1340 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1341
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345
Andre Guedes8c156c32011-07-07 10:30:36 -03001346 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001348 sec_level = BT_SECURITY_MEDIUM;
1349 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001351 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001353
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001354 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1355 if (entry)
1356 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1357 auth_type);
1358 else
1359 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1360 auth_type);
1361
Ville Tervo30e76272011-02-22 16:10:53 -03001362 if (IS_ERR(conn)) {
1363 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001364 goto unlock;
1365 }
1366
1367 if (conn->connect_cfm_cb) {
1368 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370 goto unlock;
1371 }
1372
Szymon Janc4e51eae2011-02-25 19:05:48 +01001373 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001374 if (!cmd) {
1375 err = -ENOMEM;
1376 hci_conn_put(conn);
1377 goto unlock;
1378 }
1379
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001380 /* For LE, just connecting isn't a proof that the pairing finished */
1381 if (!entry)
1382 conn->connect_cfm_cb = pairing_complete_cb;
1383
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384 conn->security_cfm_cb = pairing_complete_cb;
1385 conn->disconn_cfm_cb = pairing_complete_cb;
1386 conn->io_capability = cp->io_cap;
1387 cmd->user_data = conn;
1388
1389 if (conn->state == BT_CONNECTED &&
1390 hci_conn_security(conn, sec_level, auth_type))
1391 pairing_complete(cmd, 0);
1392
1393 err = 0;
1394
1395unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001396 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001397 hci_dev_put(hdev);
1398
1399 return err;
1400}
1401
Szymon Janc4e51eae2011-02-25 19:05:48 +01001402static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1403 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001404{
1405 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001406 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001407 struct pending_cmd *cmd;
1408 struct hci_dev *hdev;
1409 int err;
1410
1411 BT_DBG("");
1412
Johan Hedberga5c29682011-02-19 12:05:57 -03001413 if (success) {
1414 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1415 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1416 } else {
1417 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1418 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1419 }
1420
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421 if (len != sizeof(*cp))
1422 return cmd_status(sk, index, mgmt_op, EINVAL);
1423
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001425 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001427
Andre Guedes8c156c32011-07-07 10:30:36 -03001428 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001429
Johan Hedberga5c29682011-02-19 12:05:57 -03001430 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001432 goto failed;
1433 }
1434
Szymon Janc4e51eae2011-02-25 19:05:48 +01001435 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001436 if (!cmd) {
1437 err = -ENOMEM;
1438 goto failed;
1439 }
1440
1441 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001442 if (err < 0)
1443 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001444
1445failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001446 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001447 hci_dev_put(hdev);
1448
1449 return err;
1450}
1451
Johan Hedbergb312b1612011-03-16 14:29:37 +02001452static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1453 u16 len)
1454{
1455 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1456 struct hci_cp_write_local_name hci_cp;
1457 struct hci_dev *hdev;
1458 struct pending_cmd *cmd;
1459 int err;
1460
1461 BT_DBG("");
1462
1463 if (len != sizeof(*mgmt_cp))
1464 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1465
1466 hdev = hci_dev_get(index);
1467 if (!hdev)
1468 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1469
Andre Guedes8c156c32011-07-07 10:30:36 -03001470 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001471
1472 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1473 if (!cmd) {
1474 err = -ENOMEM;
1475 goto failed;
1476 }
1477
1478 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1479 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1480 &hci_cp);
1481 if (err < 0)
1482 mgmt_pending_remove(cmd);
1483
1484failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001485 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001486 hci_dev_put(hdev);
1487
1488 return err;
1489}
1490
Szymon Jancc35938b2011-03-22 13:12:21 +01001491static int read_local_oob_data(struct sock *sk, u16 index)
1492{
1493 struct hci_dev *hdev;
1494 struct pending_cmd *cmd;
1495 int err;
1496
1497 BT_DBG("hci%u", index);
1498
1499 hdev = hci_dev_get(index);
1500 if (!hdev)
1501 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1502 ENODEV);
1503
Andre Guedes8c156c32011-07-07 10:30:36 -03001504 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001505
1506 if (!test_bit(HCI_UP, &hdev->flags)) {
1507 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1508 ENETDOWN);
1509 goto unlock;
1510 }
1511
1512 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1513 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1514 EOPNOTSUPP);
1515 goto unlock;
1516 }
1517
1518 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1519 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1520 goto unlock;
1521 }
1522
1523 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1524 if (!cmd) {
1525 err = -ENOMEM;
1526 goto unlock;
1527 }
1528
1529 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1530 if (err < 0)
1531 mgmt_pending_remove(cmd);
1532
1533unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001534 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001535 hci_dev_put(hdev);
1536
1537 return err;
1538}
1539
Szymon Janc2763eda2011-03-22 13:12:22 +01001540static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1541 u16 len)
1542{
1543 struct hci_dev *hdev;
1544 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1545 int err;
1546
1547 BT_DBG("hci%u ", index);
1548
1549 if (len != sizeof(*cp))
1550 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1551 EINVAL);
1552
1553 hdev = hci_dev_get(index);
1554 if (!hdev)
1555 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1556 ENODEV);
1557
Andre Guedes8c156c32011-07-07 10:30:36 -03001558 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001559
1560 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1561 cp->randomizer);
1562 if (err < 0)
1563 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1564 else
1565 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1566 0);
1567
Andre Guedes8c156c32011-07-07 10:30:36 -03001568 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001569 hci_dev_put(hdev);
1570
1571 return err;
1572}
1573
1574static int remove_remote_oob_data(struct sock *sk, u16 index,
1575 unsigned char *data, u16 len)
1576{
1577 struct hci_dev *hdev;
1578 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1579 int err;
1580
1581 BT_DBG("hci%u ", index);
1582
1583 if (len != sizeof(*cp))
1584 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1585 EINVAL);
1586
1587 hdev = hci_dev_get(index);
1588 if (!hdev)
1589 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1590 ENODEV);
1591
Andre Guedes8c156c32011-07-07 10:30:36 -03001592 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001593
1594 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1595 if (err < 0)
1596 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1597 -err);
1598 else
1599 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1600 NULL, 0);
1601
Andre Guedes8c156c32011-07-07 10:30:36 -03001602 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001603 hci_dev_put(hdev);
1604
1605 return err;
1606}
1607
Johan Hedberg14a53662011-04-27 10:29:56 -04001608static int start_discovery(struct sock *sk, u16 index)
1609{
1610 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1611 struct hci_cp_inquiry cp;
1612 struct pending_cmd *cmd;
1613 struct hci_dev *hdev;
1614 int err;
1615
1616 BT_DBG("hci%u", index);
1617
1618 hdev = hci_dev_get(index);
1619 if (!hdev)
1620 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1621
1622 hci_dev_lock_bh(hdev);
1623
1624 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1625 if (!cmd) {
1626 err = -ENOMEM;
1627 goto failed;
1628 }
1629
1630 memset(&cp, 0, sizeof(cp));
1631 memcpy(&cp.lap, lap, 3);
1632 cp.length = 0x08;
1633 cp.num_rsp = 0x00;
1634
1635 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1636 if (err < 0)
1637 mgmt_pending_remove(cmd);
1638
1639failed:
1640 hci_dev_unlock_bh(hdev);
1641 hci_dev_put(hdev);
1642
1643 return err;
1644}
1645
1646static int stop_discovery(struct sock *sk, u16 index)
1647{
1648 struct hci_dev *hdev;
1649 struct pending_cmd *cmd;
1650 int err;
1651
1652 BT_DBG("hci%u", index);
1653
1654 hdev = hci_dev_get(index);
1655 if (!hdev)
1656 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1657
1658 hci_dev_lock_bh(hdev);
1659
1660 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1661 if (!cmd) {
1662 err = -ENOMEM;
1663 goto failed;
1664 }
1665
1666 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1667 if (err < 0)
1668 mgmt_pending_remove(cmd);
1669
1670failed:
1671 hci_dev_unlock_bh(hdev);
1672 hci_dev_put(hdev);
1673
1674 return err;
1675}
1676
Antti Julku7fbec222011-06-15 12:01:15 +03001677static int block_device(struct sock *sk, u16 index, unsigned char *data,
1678 u16 len)
1679{
1680 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001681 struct pending_cmd *cmd;
1682 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001683 int err;
1684
1685 BT_DBG("hci%u", index);
1686
Antti Julku7fbec222011-06-15 12:01:15 +03001687 if (len != sizeof(*cp))
1688 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1689 EINVAL);
1690
1691 hdev = hci_dev_get(index);
1692 if (!hdev)
1693 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1694 ENODEV);
1695
Antti Julku5e762442011-08-25 16:48:02 +03001696 hci_dev_lock_bh(hdev);
1697
1698 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1699 if (!cmd) {
1700 err = -ENOMEM;
1701 goto failed;
1702 }
1703
Antti Julku7fbec222011-06-15 12:01:15 +03001704 err = hci_blacklist_add(hdev, &cp->bdaddr);
1705
1706 if (err < 0)
1707 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1708 else
1709 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1710 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001711
1712 mgmt_pending_remove(cmd);
1713
1714failed:
1715 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001716 hci_dev_put(hdev);
1717
1718 return err;
1719}
1720
1721static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1722 u16 len)
1723{
1724 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001725 struct pending_cmd *cmd;
1726 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001727 int err;
1728
1729 BT_DBG("hci%u", index);
1730
Antti Julku7fbec222011-06-15 12:01:15 +03001731 if (len != sizeof(*cp))
1732 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1733 EINVAL);
1734
1735 hdev = hci_dev_get(index);
1736 if (!hdev)
1737 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1738 ENODEV);
1739
Antti Julku5e762442011-08-25 16:48:02 +03001740 hci_dev_lock_bh(hdev);
1741
1742 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1743 if (!cmd) {
1744 err = -ENOMEM;
1745 goto failed;
1746 }
1747
Antti Julku7fbec222011-06-15 12:01:15 +03001748 err = hci_blacklist_del(hdev, &cp->bdaddr);
1749
1750 if (err < 0)
1751 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1752 else
1753 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1754 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001755
1756 mgmt_pending_remove(cmd);
1757
1758failed:
1759 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001760 hci_dev_put(hdev);
1761
1762 return err;
1763}
1764
Antti Julkuf6422ec2011-06-22 13:11:56 +03001765static int set_fast_connectable(struct sock *sk, u16 index,
1766 unsigned char *data, u16 len)
1767{
1768 struct hci_dev *hdev;
1769 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1770 struct hci_cp_write_page_scan_activity acp;
1771 u8 type;
1772 int err;
1773
1774 BT_DBG("hci%u", index);
1775
1776 if (len != sizeof(*cp))
1777 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1778 EINVAL);
1779
1780 hdev = hci_dev_get(index);
1781 if (!hdev)
1782 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1783 ENODEV);
1784
1785 hci_dev_lock(hdev);
1786
1787 if (cp->enable) {
1788 type = PAGE_SCAN_TYPE_INTERLACED;
1789 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1790 } else {
1791 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1792 acp.interval = 0x0800; /* default 1.28 sec page scan */
1793 }
1794
1795 acp.window = 0x0012; /* default 11.25 msec page scan window */
1796
1797 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1798 sizeof(acp), &acp);
1799 if (err < 0) {
1800 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1801 -err);
1802 goto done;
1803 }
1804
1805 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1806 if (err < 0) {
1807 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1808 -err);
1809 goto done;
1810 }
1811
1812 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1813 NULL, 0);
1814done:
1815 hci_dev_unlock(hdev);
1816 hci_dev_put(hdev);
1817
1818 return err;
1819}
1820
Johan Hedberg03811012010-12-08 00:21:06 +02001821int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1822{
1823 unsigned char *buf;
1824 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001825 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001826 int err;
1827
1828 BT_DBG("got %zu bytes", msglen);
1829
1830 if (msglen < sizeof(*hdr))
1831 return -EINVAL;
1832
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001833 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001834 if (!buf)
1835 return -ENOMEM;
1836
1837 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1838 err = -EFAULT;
1839 goto done;
1840 }
1841
1842 hdr = (struct mgmt_hdr *) buf;
1843 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001844 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001845 len = get_unaligned_le16(&hdr->len);
1846
1847 if (len != msglen - sizeof(*hdr)) {
1848 err = -EINVAL;
1849 goto done;
1850 }
1851
1852 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001853 case MGMT_OP_READ_VERSION:
1854 err = read_version(sk);
1855 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001856 case MGMT_OP_READ_INDEX_LIST:
1857 err = read_index_list(sk);
1858 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001859 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001861 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001862 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001864 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001865 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001867 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001868 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001870 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001871 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001873 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001874 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 break;
1877 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001880 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 break;
1883 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001885 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001886 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001887 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888 break;
1889 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001892 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001895 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001896 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001897 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900 break;
1901 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001904 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001907 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001908 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001910 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001911 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 break;
1913 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001916 case MGMT_OP_SET_LOCAL_NAME:
1917 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1918 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001919 case MGMT_OP_READ_LOCAL_OOB_DATA:
1920 err = read_local_oob_data(sk, index);
1921 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001922 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1923 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1924 break;
1925 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1926 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1927 len);
1928 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001929 case MGMT_OP_START_DISCOVERY:
1930 err = start_discovery(sk, index);
1931 break;
1932 case MGMT_OP_STOP_DISCOVERY:
1933 err = stop_discovery(sk, index);
1934 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001935 case MGMT_OP_BLOCK_DEVICE:
1936 err = block_device(sk, index, buf + sizeof(*hdr), len);
1937 break;
1938 case MGMT_OP_UNBLOCK_DEVICE:
1939 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1940 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001941 case MGMT_OP_SET_FAST_CONNECTABLE:
1942 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1943 len);
1944 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001945 default:
1946 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001947 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001948 break;
1949 }
1950
Johan Hedberge41d8b42010-12-13 21:07:03 +02001951 if (err < 0)
1952 goto done;
1953
Johan Hedberg03811012010-12-08 00:21:06 +02001954 err = msglen;
1955
1956done:
1957 kfree(buf);
1958 return err;
1959}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001960
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001961int mgmt_index_added(u16 index)
1962{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001963 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001964}
1965
1966int mgmt_index_removed(u16 index)
1967{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001968 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001969}
1970
Johan Hedberg73f22f62010-12-29 16:00:25 +02001971struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001972 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001973 struct sock *sk;
1974};
1975
Johan Hedberg72a734e2010-12-30 00:38:22 +02001976static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001977{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001978 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001979 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001980
Johan Hedberg72a734e2010-12-30 00:38:22 +02001981 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982 return;
1983
Johan Hedberg053f0212011-01-26 13:07:10 +02001984 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985
1986 list_del(&cmd->list);
1987
1988 if (match->sk == NULL) {
1989 match->sk = cmd->sk;
1990 sock_hold(match->sk);
1991 }
1992
1993 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001994}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001995
1996int mgmt_powered(u16 index, u8 powered)
1997{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001998 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001999 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002001
Johan Hedberg72a734e2010-12-30 00:38:22 +02002002 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002003
Johan Hedberg72a734e2010-12-30 00:38:22 +02002004 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005
Szymon Janc4e51eae2011-02-25 19:05:48 +01002006 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002007
2008 if (match.sk)
2009 sock_put(match.sk);
2010
2011 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002012}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002013
Johan Hedberg73f22f62010-12-29 16:00:25 +02002014int mgmt_discoverable(u16 index, u8 discoverable)
2015{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002016 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002017 struct cmd_lookup match = { discoverable, NULL };
2018 int ret;
2019
Szymon Jancb8534e02011-03-01 16:55:34 +01002020 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002021
Johan Hedberg72a734e2010-12-30 00:38:22 +02002022 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002023
Szymon Janc4e51eae2011-02-25 19:05:48 +01002024 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2025 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002026
2027 if (match.sk)
2028 sock_put(match.sk);
2029
2030 return ret;
2031}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002032
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002033int mgmt_connectable(u16 index, u8 connectable)
2034{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002035 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002036 struct cmd_lookup match = { connectable, NULL };
2037 int ret;
2038
Johan Hedberg72a734e2010-12-30 00:38:22 +02002039 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002040
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002042
Szymon Janc4e51eae2011-02-25 19:05:48 +01002043 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002044
2045 if (match.sk)
2046 sock_put(match.sk);
2047
2048 return ret;
2049}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002050
Johan Hedberg4df378a2011-04-28 11:29:03 -07002051int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002052{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002053 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002054
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002055 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002056
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002057 ev.store_hint = persistent;
2058 bacpy(&ev.key.bdaddr, &key->bdaddr);
2059 ev.key.type = key->type;
2060 memcpy(ev.key.val, key->val, 16);
2061 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002062
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002063 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002064}
Johan Hedbergf7520542011-01-20 12:34:39 +02002065
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002066int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002067{
2068 struct mgmt_ev_connected ev;
2069
Johan Hedbergf7520542011-01-20 12:34:39 +02002070 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002071 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002072
Szymon Janc4e51eae2011-02-25 19:05:48 +01002073 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002074}
2075
Johan Hedberg8962ee72011-01-20 12:40:27 +02002076static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2077{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002078 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002079 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002080 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002081
Johan Hedberga38528f2011-01-22 06:46:43 +02002082 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002083
Szymon Janc4e51eae2011-02-25 19:05:48 +01002084 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002085
2086 *sk = cmd->sk;
2087 sock_hold(*sk);
2088
Johan Hedberga664b5b2011-02-19 12:06:02 -03002089 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002090}
2091
Johan Hedbergf7520542011-01-20 12:34:39 +02002092int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2093{
2094 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002095 struct sock *sk = NULL;
2096 int err;
2097
2098 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002099
Johan Hedbergf7520542011-01-20 12:34:39 +02002100 bacpy(&ev.bdaddr, bdaddr);
2101
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002103
2104 if (sk)
2105 sock_put(sk);
2106
2107 return err;
2108}
2109
2110int mgmt_disconnect_failed(u16 index)
2111{
2112 struct pending_cmd *cmd;
2113 int err;
2114
2115 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2116 if (!cmd)
2117 return -ENOENT;
2118
Szymon Janc4e51eae2011-02-25 19:05:48 +01002119 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002120
Johan Hedberga664b5b2011-02-19 12:06:02 -03002121 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002122
2123 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002124}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002125
2126int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2127{
2128 struct mgmt_ev_connect_failed ev;
2129
Johan Hedberg17d5c042011-01-22 06:09:08 +02002130 bacpy(&ev.bdaddr, bdaddr);
2131 ev.status = status;
2132
Szymon Janc4e51eae2011-02-25 19:05:48 +01002133 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002134}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002135
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002136int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137{
2138 struct mgmt_ev_pin_code_request ev;
2139
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002141 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142
Szymon Janc4e51eae2011-02-25 19:05:48 +01002143 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2144 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145}
2146
2147int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2148{
2149 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002150 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002151 int err;
2152
2153 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2154 if (!cmd)
2155 return -ENOENT;
2156
Johan Hedbergac56fb12011-02-19 12:05:59 -03002157 bacpy(&rp.bdaddr, bdaddr);
2158 rp.status = status;
2159
Szymon Janc4e51eae2011-02-25 19:05:48 +01002160 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2161 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002162
Johan Hedberga664b5b2011-02-19 12:06:02 -03002163 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002164
2165 return err;
2166}
2167
2168int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2169{
2170 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002171 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172 int err;
2173
2174 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2175 if (!cmd)
2176 return -ENOENT;
2177
Johan Hedbergac56fb12011-02-19 12:05:59 -03002178 bacpy(&rp.bdaddr, bdaddr);
2179 rp.status = status;
2180
Szymon Janc4e51eae2011-02-25 19:05:48 +01002181 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2182 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002183
Johan Hedberga664b5b2011-02-19 12:06:02 -03002184 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
2186 return err;
2187}
Johan Hedberga5c29682011-02-19 12:05:57 -03002188
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002189int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2190 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002191{
2192 struct mgmt_ev_user_confirm_request ev;
2193
2194 BT_DBG("hci%u", index);
2195
Johan Hedberga5c29682011-02-19 12:05:57 -03002196 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002197 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002198 put_unaligned_le32(value, &ev.value);
2199
Szymon Janc4e51eae2011-02-25 19:05:48 +01002200 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2201 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002202}
2203
2204static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2205 u8 opcode)
2206{
2207 struct pending_cmd *cmd;
2208 struct mgmt_rp_user_confirm_reply rp;
2209 int err;
2210
2211 cmd = mgmt_pending_find(opcode, index);
2212 if (!cmd)
2213 return -ENOENT;
2214
Johan Hedberga5c29682011-02-19 12:05:57 -03002215 bacpy(&rp.bdaddr, bdaddr);
2216 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002217 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002218
Johan Hedberga664b5b2011-02-19 12:06:02 -03002219 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002220
2221 return err;
2222}
2223
2224int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2225{
2226 return confirm_reply_complete(index, bdaddr, status,
2227 MGMT_OP_USER_CONFIRM_REPLY);
2228}
2229
Szymon Jancb8534e02011-03-01 16:55:34 +01002230int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002231{
2232 return confirm_reply_complete(index, bdaddr, status,
2233 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2234}
Johan Hedberg2a611692011-02-19 12:06:00 -03002235
2236int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2237{
2238 struct mgmt_ev_auth_failed ev;
2239
Johan Hedberg2a611692011-02-19 12:06:00 -03002240 bacpy(&ev.bdaddr, bdaddr);
2241 ev.status = status;
2242
Szymon Janc4e51eae2011-02-25 19:05:48 +01002243 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002244}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002245
2246int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2247{
2248 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002249 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002250 struct mgmt_cp_set_local_name ev;
2251 int err;
2252
2253 memset(&ev, 0, sizeof(ev));
2254 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2255
2256 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2257 if (!cmd)
2258 goto send_event;
2259
2260 if (status) {
2261 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2262 goto failed;
2263 }
2264
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002265 hdev = hci_dev_get(index);
2266 if (hdev) {
2267 hci_dev_lock_bh(hdev);
2268 update_eir(hdev);
2269 hci_dev_unlock_bh(hdev);
2270 hci_dev_put(hdev);
2271 }
2272
Johan Hedbergb312b1612011-03-16 14:29:37 +02002273 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2274 sizeof(ev));
2275 if (err < 0)
2276 goto failed;
2277
2278send_event:
2279 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2280 cmd ? cmd->sk : NULL);
2281
2282failed:
2283 if (cmd)
2284 mgmt_pending_remove(cmd);
2285 return err;
2286}
Szymon Jancc35938b2011-03-22 13:12:21 +01002287
2288int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2289 u8 status)
2290{
2291 struct pending_cmd *cmd;
2292 int err;
2293
2294 BT_DBG("hci%u status %u", index, status);
2295
2296 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2297 if (!cmd)
2298 return -ENOENT;
2299
2300 if (status) {
2301 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2302 EIO);
2303 } else {
2304 struct mgmt_rp_read_local_oob_data rp;
2305
2306 memcpy(rp.hash, hash, sizeof(rp.hash));
2307 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2308
2309 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2310 &rp, sizeof(rp));
2311 }
2312
2313 mgmt_pending_remove(cmd);
2314
2315 return err;
2316}
Johan Hedberge17acd42011-03-30 23:57:16 +03002317
2318int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2319 u8 *eir)
2320{
2321 struct mgmt_ev_device_found ev;
2322
2323 memset(&ev, 0, sizeof(ev));
2324
2325 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002326 ev.rssi = rssi;
2327
2328 if (eir)
2329 memcpy(ev.eir, eir, sizeof(ev.eir));
2330
Andre Guedesf8523592011-09-09 18:56:26 -03002331 if (dev_class)
2332 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2333
Johan Hedberge17acd42011-03-30 23:57:16 +03002334 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2335}
Johan Hedberga88a9652011-03-30 13:18:12 +03002336
2337int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2338{
2339 struct mgmt_ev_remote_name ev;
2340
2341 memset(&ev, 0, sizeof(ev));
2342
2343 bacpy(&ev.bdaddr, bdaddr);
2344 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2345
2346 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2347}
Johan Hedberg314b2382011-04-27 10:29:57 -04002348
2349int mgmt_discovering(u16 index, u8 discovering)
2350{
2351 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2352 sizeof(discovering), NULL);
2353}
Antti Julku5e762442011-08-25 16:48:02 +03002354
2355int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2356{
2357 struct pending_cmd *cmd;
2358 struct mgmt_ev_device_blocked ev;
2359
2360 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2361
2362 bacpy(&ev.bdaddr, bdaddr);
2363
2364 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2365 cmd ? cmd->sk : NULL);
2366}
2367
2368int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2369{
2370 struct pending_cmd *cmd;
2371 struct mgmt_ev_device_unblocked ev;
2372
2373 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2374
2375 bacpy(&ev.bdaddr, bdaddr);
2376
2377 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2378 cmd ? cmd->sk : NULL);
2379}