blob: 424f2df11cfccd8e7279a95c3c5be6119c4e72c5 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070030#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020031#include <net/bluetooth/mgmt.h>
Brian Gixa68668b2011-08-11 15:49:36 -070032#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020033
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Brian Gixa68668b2011-08-11 15:49:36 -070037enum scan_mode {
38 SCAN_IDLE,
39 SCAN_LE,
40 SCAN_BR
41};
42
43struct disco_interleave {
44 struct timer_list timer;
45 struct timer_list le_timer;
46 u16 index;
47 enum scan_mode mode;
48 int int_phase;
49 int int_count;
50};
51
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020052struct pending_cmd {
53 struct list_head list;
54 __u16 opcode;
55 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010056 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030058 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020059};
60
Mat Martineau8cd0df02011-08-23 16:23:36 -070061struct mgmt_pending_free_work {
62 struct work_struct work;
63 struct sock *sk;
64};
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020067
Szymon Janc4e51eae2011-02-25 19:05:48 +010068static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020069{
70 struct sk_buff *skb;
71 struct mgmt_hdr *hdr;
72 struct mgmt_ev_cmd_status *ev;
73
Szymon Janc34eb5252011-02-28 14:10:08 +010074 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020075
76 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
77 if (!skb)
78 return -ENOMEM;
79
80 hdr = (void *) skb_put(skb, sizeof(*hdr));
81
82 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010083 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020084 hdr->len = cpu_to_le16(sizeof(*ev));
85
86 ev = (void *) skb_put(skb, sizeof(*ev));
87 ev->status = status;
88 put_unaligned_le16(cmd, &ev->opcode);
89
90 if (sock_queue_rcv_skb(sk, skb) < 0)
91 kfree_skb(skb);
92
93 return 0;
94}
95
Szymon Janc4e51eae2011-02-25 19:05:48 +010096static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
97 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020098{
99 struct sk_buff *skb;
100 struct mgmt_hdr *hdr;
101 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +0200102
103 BT_DBG("sock %p", sk);
104
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 if (!skb)
107 return -ENOMEM;
108
109 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200110
Johan Hedberg02d98122010-12-13 21:07:04 +0200111 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100112 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200113 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200114
Johan Hedberga38528f2011-01-22 06:46:43 +0200115 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
116 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100117
118 if (rp)
119 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200120
121 if (sock_queue_rcv_skb(sk, skb) < 0)
122 kfree_skb(skb);
123
124 return 0;
125}
126
Johan Hedberga38528f2011-01-22 06:46:43 +0200127static int read_version(struct sock *sk)
128{
129 struct mgmt_rp_read_version rp;
130
131 BT_DBG("sock %p", sk);
132
133 rp.version = MGMT_VERSION;
134 put_unaligned_le16(MGMT_REVISION, &rp.revision);
135
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
137 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200138}
139
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140static int read_index_list(struct sock *sk)
141{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142 struct mgmt_rp_read_index_list *rp;
143 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200144 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200145 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200146 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147
148 BT_DBG("sock %p", sk);
149
150 read_lock(&hci_dev_list_lock);
151
152 count = 0;
153 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700154 struct hci_dev *d = list_entry(p, struct hci_dev, list);
155 if (d->dev_type != HCI_BREDR)
156 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200157 count++;
158 }
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 rp_len = sizeof(*rp) + (2 * count);
161 rp = kmalloc(rp_len, GFP_ATOMIC);
162 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100163 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200164 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100165 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166
Brian Gixa68668b2011-08-11 15:49:36 -0700167 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200168
169 i = 0;
170 list_for_each(p, &hci_dev_list) {
171 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172
173 hci_del_off_timer(d);
174
Peter Krystad1fc44072011-08-30 15:38:12 -0700175 if (d->dev_type != HCI_BREDR)
176 continue;
177
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200178 set_bit(HCI_MGMT, &d->flags);
179
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200180 if (test_bit(HCI_SETUP, &d->flags))
181 continue;
182
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200183 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700184 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200185 BT_DBG("Added hci%u", d->id);
186 }
187
188 read_unlock(&hci_dev_list_lock);
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
191 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 kfree(rp);
194
195 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200199{
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200202
Szymon Janc4e51eae2011-02-25 19:05:48 +0100203 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200204
Szymon Janc4e51eae2011-02-25 19:05:48 +0100205 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100207 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200209 hci_del_off_timer(hdev);
210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200213 set_bit(HCI_MGMT, &hdev->flags);
214
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200215 memset(&rp, 0, sizeof(rp));
216
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.powered = test_bit(HCI_UP, &hdev->flags);
220 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
221 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
222 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223
224 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200225 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200227 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200229 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200230
Johan Hedberga38528f2011-01-22 06:46:43 +0200231 bacpy(&rp.bdaddr, &hdev->bdaddr);
232 memcpy(rp.features, hdev->features, 8);
233 memcpy(rp.dev_class, hdev->dev_class, 3);
234 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
235 rp.hci_ver = hdev->hci_ver;
236 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200237
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200238 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200241 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200242
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200244}
245
Mat Martineau8cd0df02011-08-23 16:23:36 -0700246static void mgmt_pending_free_worker(struct work_struct *work)
247{
248 struct mgmt_pending_free_work *free_work =
249 container_of(work, struct mgmt_pending_free_work, work);
250
251 BT_DBG("sk %p", free_work->sk);
252
253 sock_put(free_work->sk);
254 kfree(free_work);
255}
256
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200257static void mgmt_pending_free(struct pending_cmd *cmd)
258{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700259 struct mgmt_pending_free_work *free_work;
260 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700261
Mat Martineau8cd0df02011-08-23 16:23:36 -0700262 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
263
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100264 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200265 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700266
267 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
268 if (free_work) {
269 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
270 free_work->sk = sk;
271
272 if (!schedule_work(&free_work->work))
273 kfree(free_work);
274 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200275}
276
Johan Hedberg366a0332011-02-19 12:05:55 -0300277static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
278 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200279{
280 struct pending_cmd *cmd;
281
Brian Gixa68668b2011-08-11 15:49:36 -0700282 BT_DBG("%d", opcode);
283
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200284 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
285 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300286 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200287
288 cmd->opcode = opcode;
289 cmd->index = index;
290
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100291 cmd->param = kmalloc(len, GFP_ATOMIC);
292 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200293 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300294 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200295 }
296
Szymon Janc8fce6352011-03-22 13:12:20 +0100297 if (data)
298 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299
300 cmd->sk = sk;
301 sock_hold(sk);
302
303 list_add(&cmd->list, &cmd_list);
304
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306}
307
308static void mgmt_pending_foreach(u16 opcode, int index,
309 void (*cb)(struct pending_cmd *cmd, void *data),
310 void *data)
311{
312 struct list_head *p, *n;
313
Brian Gixa68668b2011-08-11 15:49:36 -0700314 BT_DBG(" %d", opcode);
315
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 list_for_each_safe(p, n, &cmd_list) {
317 struct pending_cmd *cmd;
318
319 cmd = list_entry(p, struct pending_cmd, list);
320
321 if (cmd->opcode != opcode)
322 continue;
323
324 if (index >= 0 && cmd->index != index)
325 continue;
326
327 cb(cmd, data);
328 }
329}
330
331static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
332{
333 struct list_head *p;
334
Brian Gixa68668b2011-08-11 15:49:36 -0700335 BT_DBG(" %d", opcode);
336
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337 list_for_each(p, &cmd_list) {
338 struct pending_cmd *cmd;
339
340 cmd = list_entry(p, struct pending_cmd, list);
341
342 if (cmd->opcode != opcode)
343 continue;
344
345 if (index >= 0 && cmd->index != index)
346 continue;
347
348 return cmd;
349 }
350
351 return NULL;
352}
353
Johan Hedberga664b5b2011-02-19 12:06:02 -0300354static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355{
Brian Gixa68668b2011-08-11 15:49:36 -0700356 BT_DBG(" %d", cmd->opcode);
357
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 list_del(&cmd->list);
359 mgmt_pending_free(cmd);
360}
361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200364 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200365 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300366 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300367 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200368
369 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200370
Szymon Janc4e51eae2011-02-25 19:05:48 +0100371 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200372
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100373 if (len != sizeof(*cp))
374 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
375
Szymon Janc4e51eae2011-02-25 19:05:48 +0100376 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200381
382 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200383 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100384 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200385 goto failed;
386 }
387
Szymon Janc4e51eae2011-02-25 19:05:48 +0100388 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
389 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200390 goto failed;
391 }
392
Szymon Janc4e51eae2011-02-25 19:05:48 +0100393 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 if (!cmd) {
395 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300397 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200400 queue_work(hdev->workqueue, &hdev->power_on);
401 else
402 queue_work(hdev->workqueue, &hdev->power_off);
403
Johan Hedberg366a0332011-02-19 12:05:55 -0300404 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200405
406failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200408 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300409 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200410}
411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
413 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200414{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200415 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200416 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300417 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200418 u8 scan;
419 int err;
420
421 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200424
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100425 if (len != sizeof(*cp))
426 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
427
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200429 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200433
434 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200436 goto failed;
437 }
438
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
441 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200442 goto failed;
443 }
444
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200446 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100447 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200448 goto failed;
449 }
450
Szymon Janc4e51eae2011-02-25 19:05:48 +0100451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300452 if (!cmd) {
453 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200454 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300455 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200456
457 scan = SCAN_PAGE;
458
Johan Hedberg72a734e2010-12-30 00:38:22 +0200459 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200460 scan |= SCAN_INQUIRY;
461
462 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
463 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300464 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200465
466failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200468 hci_dev_put(hdev);
469
470 return err;
471}
472
Szymon Janc4e51eae2011-02-25 19:05:48 +0100473static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
474 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200475{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200476 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200477 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300478 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200479 u8 scan;
480 int err;
481
482 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200483
Szymon Janc4e51eae2011-02-25 19:05:48 +0100484 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200485
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100486 if (len != sizeof(*cp))
487 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200490 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100491 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200494
495 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100496 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200497 goto failed;
498 }
499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
501 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
502 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200503 goto failed;
504 }
505
Johan Hedberg72a734e2010-12-30 00:38:22 +0200506 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200508 goto failed;
509 }
510
Szymon Janc4e51eae2011-02-25 19:05:48 +0100511 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300512 if (!cmd) {
513 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200514 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300515 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200516
Johan Hedberg72a734e2010-12-30 00:38:22 +0200517 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200518 scan = SCAN_PAGE;
519 else
520 scan = 0;
521
522 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
523 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300524 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200525
526failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200528 hci_dev_put(hdev);
529
530 return err;
531}
532
Szymon Janc4e51eae2011-02-25 19:05:48 +0100533static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
534 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200535{
536 struct sk_buff *skb;
537 struct mgmt_hdr *hdr;
538
Brian Gixa68668b2011-08-11 15:49:36 -0700539 BT_DBG("hci%d %d", index, event);
540
Johan Hedbergc542a062011-01-26 13:11:03 +0200541 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
542 if (!skb)
543 return -ENOMEM;
544
545 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
546
547 hdr = (void *) skb_put(skb, sizeof(*hdr));
548 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100549 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200550 hdr->len = cpu_to_le16(data_len);
551
Szymon Janc4e51eae2011-02-25 19:05:48 +0100552 if (data)
553 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200554
555 hci_send_to_sock(NULL, skb, skip_sk);
556 kfree_skb(skb);
557
558 return 0;
559}
560
Johan Hedberg053f0212011-01-26 13:07:10 +0200561static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
562{
Johan Hedberga38528f2011-01-22 06:46:43 +0200563 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200564
Johan Hedberga38528f2011-01-22 06:46:43 +0200565 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200566
Szymon Janc4e51eae2011-02-25 19:05:48 +0100567 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200568}
569
Szymon Janc4e51eae2011-02-25 19:05:48 +0100570static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
571 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200572{
573 struct mgmt_mode *cp, ev;
574 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200575 int err;
576
577 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200578
Szymon Janc4e51eae2011-02-25 19:05:48 +0100579 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200580
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100581 if (len != sizeof(*cp))
582 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
583
Szymon Janc4e51eae2011-02-25 19:05:48 +0100584 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200585 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100586 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200589
590 if (cp->val)
591 set_bit(HCI_PAIRABLE, &hdev->flags);
592 else
593 clear_bit(HCI_PAIRABLE, &hdev->flags);
594
Szymon Janc4e51eae2011-02-25 19:05:48 +0100595 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200596 if (err < 0)
597 goto failed;
598
Johan Hedbergc542a062011-01-26 13:11:03 +0200599 ev.val = cp->val;
600
Szymon Janc4e51eae2011-02-25 19:05:48 +0100601 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200602
603failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200605 hci_dev_put(hdev);
606
607 return err;
608}
609
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300610#define EIR_FLAGS 0x01 /* flags */
611#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
612#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
613#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
614#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
615#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
616#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
617#define EIR_NAME_SHORT 0x08 /* shortened local name */
618#define EIR_NAME_COMPLETE 0x09 /* complete local name */
619#define EIR_TX_POWER 0x0A /* transmit power level */
620#define EIR_DEVICE_ID 0x10 /* device ID */
621
622#define PNP_INFO_SVCLASS_ID 0x1200
623
624static u8 bluetooth_base_uuid[] = {
625 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
626 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627};
628
629static u16 get_uuid16(u8 *uuid128)
630{
631 u32 val;
632 int i;
633
634 for (i = 0; i < 12; i++) {
635 if (bluetooth_base_uuid[i] != uuid128[i])
636 return 0;
637 }
638
639 memcpy(&val, &uuid128[12], 4);
640
641 val = le32_to_cpu(val);
642 if (val > 0xffff)
643 return 0;
644
645 return (u16) val;
646}
647
648static void create_eir(struct hci_dev *hdev, u8 *data)
649{
650 u8 *ptr = data;
651 u16 eir_len = 0;
652 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
653 int i, truncated = 0;
654 struct list_head *p;
655 size_t name_len;
656
657 name_len = strlen(hdev->dev_name);
658
659 if (name_len > 0) {
660 /* EIR Data type */
661 if (name_len > 48) {
662 name_len = 48;
663 ptr[1] = EIR_NAME_SHORT;
664 } else
665 ptr[1] = EIR_NAME_COMPLETE;
666
667 /* EIR Data length */
668 ptr[0] = name_len + 1;
669
670 memcpy(ptr + 2, hdev->dev_name, name_len);
671
672 eir_len += (name_len + 2);
673 ptr += (name_len + 2);
674 }
675
676 memset(uuid16_list, 0, sizeof(uuid16_list));
677
678 /* Group all UUID16 types */
679 list_for_each(p, &hdev->uuids) {
680 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
681 u16 uuid16;
682
683 uuid16 = get_uuid16(uuid->uuid);
684 if (uuid16 == 0)
685 return;
686
687 if (uuid16 < 0x1100)
688 continue;
689
690 if (uuid16 == PNP_INFO_SVCLASS_ID)
691 continue;
692
693 /* Stop if not enough space to put next UUID */
694 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
695 truncated = 1;
696 break;
697 }
698
699 /* Check for duplicates */
700 for (i = 0; uuid16_list[i] != 0; i++)
701 if (uuid16_list[i] == uuid16)
702 break;
703
704 if (uuid16_list[i] == 0) {
705 uuid16_list[i] = uuid16;
706 eir_len += sizeof(u16);
707 }
708 }
709
710 if (uuid16_list[0] != 0) {
711 u8 *length = ptr;
712
713 /* EIR Data type */
714 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
715
716 ptr += 2;
717 eir_len += 2;
718
719 for (i = 0; uuid16_list[i] != 0; i++) {
720 *ptr++ = (uuid16_list[i] & 0x00ff);
721 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
722 }
723
724 /* EIR Data length */
725 *length = (i * sizeof(u16)) + 1;
726 }
727}
728
729static int update_eir(struct hci_dev *hdev)
730{
731 struct hci_cp_write_eir cp;
732
733 if (!(hdev->features[6] & LMP_EXT_INQ))
734 return 0;
735
736 if (hdev->ssp_mode == 0)
737 return 0;
738
739 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
740 return 0;
741
742 memset(&cp, 0, sizeof(cp));
743
744 create_eir(hdev, cp.data);
745
746 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
747 return 0;
748
749 memcpy(hdev->eir, cp.data, sizeof(cp.data));
750
751 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
752}
753
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200754static u8 get_service_classes(struct hci_dev *hdev)
755{
756 struct list_head *p;
757 u8 val = 0;
758
759 list_for_each(p, &hdev->uuids) {
760 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
761
762 val |= uuid->svc_hint;
763 }
764
765 return val;
766}
767
768static int update_class(struct hci_dev *hdev)
769{
770 u8 cod[3];
771
772 BT_DBG("%s", hdev->name);
773
774 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
775 return 0;
776
777 cod[0] = hdev->minor_class;
778 cod[1] = hdev->major_class;
779 cod[2] = get_service_classes(hdev);
780
781 if (memcmp(cod, hdev->dev_class, 3) == 0)
782 return 0;
783
784 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
785}
786
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788{
789 struct mgmt_cp_add_uuid *cp;
790 struct hci_dev *hdev;
791 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792 int err;
793
794 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200795
Szymon Janc4e51eae2011-02-25 19:05:48 +0100796 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200797
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100798 if (len != sizeof(*cp))
799 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
800
Szymon Janc4e51eae2011-02-25 19:05:48 +0100801 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200802 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100803 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200806
807 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
808 if (!uuid) {
809 err = -ENOMEM;
810 goto failed;
811 }
812
813 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200814 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200815
816 list_add(&uuid->list, &hdev->uuids);
817
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200818 err = update_class(hdev);
819 if (err < 0)
820 goto failed;
821
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300822 err = update_eir(hdev);
823 if (err < 0)
824 goto failed;
825
Szymon Janc4e51eae2011-02-25 19:05:48 +0100826 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200827
828failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200830 hci_dev_put(hdev);
831
832 return err;
833}
834
Szymon Janc4e51eae2011-02-25 19:05:48 +0100835static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200836{
837 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100838 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200839 struct hci_dev *hdev;
840 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 +0200841 int err, found;
842
843 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200844
Szymon Janc4e51eae2011-02-25 19:05:48 +0100845 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200846
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100847 if (len != sizeof(*cp))
848 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
849
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200851 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100852 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200855
856 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
857 err = hci_uuids_clear(hdev);
858 goto unlock;
859 }
860
861 found = 0;
862
863 list_for_each_safe(p, n, &hdev->uuids) {
864 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
865
866 if (memcmp(match->uuid, cp->uuid, 16) != 0)
867 continue;
868
869 list_del(&match->list);
870 found++;
871 }
872
873 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100874 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200875 goto unlock;
876 }
877
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878 err = update_class(hdev);
879 if (err < 0)
880 goto unlock;
881
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300882 err = update_eir(hdev);
883 if (err < 0)
884 goto unlock;
885
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887
888unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890 hci_dev_put(hdev);
891
892 return err;
893}
894
Szymon Janc4e51eae2011-02-25 19:05:48 +0100895static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
896 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897{
898 struct hci_dev *hdev;
899 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900 int err;
901
902 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200903
Szymon Janc4e51eae2011-02-25 19:05:48 +0100904 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200905
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100906 if (len != sizeof(*cp))
907 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
908
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200910 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200912
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200914
915 hdev->major_class = cp->major;
916 hdev->minor_class = cp->minor;
917
918 err = update_class(hdev);
919
920 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100921 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200924 hci_dev_put(hdev);
925
926 return err;
927}
928
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
930 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200931{
932 struct hci_dev *hdev;
933 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200934 int err;
935
936 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200937
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100938 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100939 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100940
Szymon Janc4e51eae2011-02-25 19:05:48 +0100941 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200942 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100943 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200946
Szymon Janc4e51eae2011-02-25 19:05:48 +0100947 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200948
949 if (cp->enable) {
950 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
951 err = 0;
952 } else {
953 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
954 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300955 if (err == 0)
956 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200957 }
958
959 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100960 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
961 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200962
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200964 hci_dev_put(hdev);
965
966 return err;
967}
968
Szymon Janc4e51eae2011-02-25 19:05:48 +0100969static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200970{
971 struct hci_dev *hdev;
972 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300974 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200975
976 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100977
978 if (len < sizeof(*cp))
979 return -EINVAL;
980
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200981 key_count = get_unaligned_le16(&cp->key_count);
982
983 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300984 if (expected_len > len) {
985 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
986 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200987 return -EINVAL;
988 }
989
Szymon Janc4e51eae2011-02-25 19:05:48 +0100990 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200991 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100992 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200993
Szymon Janc4e51eae2011-02-25 19:05:48 +0100994 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200995 key_count);
996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200998
999 hci_link_keys_clear(hdev);
1000
1001 set_bit(HCI_LINK_KEYS, &hdev->flags);
1002
1003 if (cp->debug_keys)
1004 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1005 else
1006 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1007
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001008 len -= sizeof(*cp);
1009 i = 0;
1010
1011 while (i < len) {
1012 struct mgmt_key_info *key = (void *) cp->keys + i;
1013
Brian Gixa68668b2011-08-11 15:49:36 -07001014 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001017 struct key_master_id *id = (void *) key->data;
1018
1019 if (key->dlen != sizeof(struct key_master_id))
1020 continue;
1021
Vinicius Costa Gomes1fa2de32011-07-08 18:31:45 -03001022 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
Brian Gixa68668b2011-08-11 15:49:36 -07001023 key->auth, id->ediv, id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001024
1025 continue;
1026 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001029 key->pin_len);
1030 }
1031
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001032 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001035 hci_dev_put(hdev);
1036
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001037 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001038}
1039
Szymon Janc4e51eae2011-02-25 19:05:48 +01001040static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001041{
1042 struct hci_dev *hdev;
1043 struct mgmt_cp_remove_key *cp;
1044 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001045 int err;
1046
1047 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001048
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001049 if (len != sizeof(*cp))
1050 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001053 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001054 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001057
1058 err = hci_remove_link_key(hdev, &cp->bdaddr);
1059 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001060 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001061 goto unlock;
1062 }
1063
1064 err = 0;
1065
1066 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1067 goto unlock;
1068
1069 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1070 if (conn) {
1071 struct hci_cp_disconnect dc;
1072
1073 put_unaligned_le16(conn->handle, &dc.handle);
1074 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001076 }
1077
1078unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080 hci_dev_put(hdev);
1081
1082 return err;
1083}
1084
Szymon Janc4e51eae2011-02-25 19:05:48 +01001085static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001086{
1087 struct hci_dev *hdev;
1088 struct mgmt_cp_disconnect *cp;
1089 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001090 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001091 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001092 int err;
1093
1094 BT_DBG("");
1095
1096 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001097
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001098 if (len != sizeof(*cp))
1099 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1100
Szymon Janc4e51eae2011-02-25 19:05:48 +01001101 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001102 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001106
1107 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001108 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001109 goto failed;
1110 }
1111
Szymon Janc4e51eae2011-02-25 19:05:48 +01001112 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1113 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001114 goto failed;
1115 }
1116
1117 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1118 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001119 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1120 if (!conn) {
1121 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1122 ENOTCONN);
1123 goto failed;
1124 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001125 }
1126
Szymon Janc4e51eae2011-02-25 19:05:48 +01001127 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001128 if (!cmd) {
1129 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001130 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001131 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001132
1133 put_unaligned_le16(conn->handle, &dc.handle);
1134 dc.reason = 0x13; /* Remote User Terminated Connection */
1135
1136 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1137 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001138 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001139
1140failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001142 hci_dev_put(hdev);
1143
1144 return err;
1145}
1146
Szymon Janc8ce62842011-03-01 16:55:32 +01001147static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001148{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001149 struct mgmt_rp_get_connections *rp;
1150 struct hci_dev *hdev;
1151 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001152 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001153 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001154 int i, err;
1155
1156 BT_DBG("");
1157
Szymon Janc4e51eae2011-02-25 19:05:48 +01001158 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001159 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001160 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001163
1164 count = 0;
1165 list_for_each(p, &hdev->conn_hash.list) {
1166 count++;
1167 }
1168
Johan Hedberga38528f2011-01-22 06:46:43 +02001169 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1170 rp = kmalloc(rp_len, GFP_ATOMIC);
1171 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001172 err = -ENOMEM;
1173 goto unlock;
1174 }
1175
Johan Hedberg2784eb42011-01-21 13:56:35 +02001176 put_unaligned_le16(count, &rp->conn_count);
1177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 read_lock(&hci_dev_list_lock);
1179
Johan Hedberg2784eb42011-01-21 13:56:35 +02001180 i = 0;
1181 list_for_each(p, &hdev->conn_hash.list) {
1182 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1183
1184 bacpy(&rp->conn[i++], &c->dst);
1185 }
1186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 read_unlock(&hci_dev_list_lock);
1188
Szymon Janc4e51eae2011-02-25 19:05:48 +01001189 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001190
1191unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001192 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001194 hci_dev_put(hdev);
1195 return err;
1196}
1197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198static int pin_code_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_reply *cp;
1203 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001204 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205 int err;
1206
1207 BT_DBG("");
1208
1209 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001211 if (len != sizeof(*cp))
1212 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1213
Szymon Janc4e51eae2011-02-25 19:05:48 +01001214 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001216 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 hci_dev_lock(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_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001222 goto failed;
1223 }
1224
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001226 if (!cmd) {
1227 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001229 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230
1231 bacpy(&reply.bdaddr, &cp->bdaddr);
1232 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234
1235 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1236 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001237 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001238
1239failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001241 hci_dev_put(hdev);
1242
1243 return err;
1244}
1245
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1247 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001248{
1249 struct hci_dev *hdev;
1250 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001252 int err;
1253
1254 BT_DBG("");
1255
1256 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001257
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001258 if (len != sizeof(*cp))
1259 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1260 EINVAL);
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001263 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1265 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001268
1269 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001270 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1271 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001272 goto failed;
1273 }
1274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1276 data, len);
1277 if (!cmd) {
1278 err = -ENOMEM;
1279 goto failed;
1280 }
1281
1282 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1283 &cp->bdaddr);
1284 if (err < 0)
1285 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001286
1287failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001289 hci_dev_put(hdev);
1290
1291 return err;
1292}
1293
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1295 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001296{
1297 struct hci_dev *hdev;
1298 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001299
1300 BT_DBG("");
1301
1302 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001303
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001304 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001305 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001306
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001308 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001309 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001312
1313 hdev->io_capability = cp->io_capability;
1314
1315 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001316 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001319 hci_dev_put(hdev);
1320
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001322}
1323
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1325{
1326 struct hci_dev *hdev = conn->hdev;
1327 struct list_head *p;
1328
1329 list_for_each(p, &cmd_list) {
1330 struct pending_cmd *cmd;
1331
1332 cmd = list_entry(p, struct pending_cmd, list);
1333
1334 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1335 continue;
1336
1337 if (cmd->index != hdev->id)
1338 continue;
1339
1340 if (cmd->user_data != conn)
1341 continue;
1342
1343 return cmd;
1344 }
1345
1346 return NULL;
1347}
1348
1349static void pairing_complete(struct pending_cmd *cmd, u8 status)
1350{
1351 struct mgmt_rp_pair_device rp;
1352 struct hci_conn *conn = cmd->user_data;
1353
Brian Gixa68668b2011-08-11 15:49:36 -07001354 BT_DBG(" %u", status);
1355
Johan Hedberge9a416b2011-02-19 12:05:56 -03001356 bacpy(&rp.bdaddr, &conn->dst);
1357 rp.status = status;
1358
Szymon Janc4e51eae2011-02-25 19:05:48 +01001359 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001360
1361 /* So we don't get further callbacks for this connection */
1362 conn->connect_cfm_cb = NULL;
1363 conn->security_cfm_cb = NULL;
1364 conn->disconn_cfm_cb = NULL;
1365
Johan Hedberga664b5b2011-02-19 12:06:02 -03001366 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001367}
1368
1369static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1370{
1371 struct pending_cmd *cmd;
1372
Brian Gixa68668b2011-08-11 15:49:36 -07001373 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001374
1375 cmd = find_pairing(conn);
1376 if (!cmd) {
1377 BT_DBG("Unable to find a pending command");
1378 return;
1379 }
1380
1381 pairing_complete(cmd, status);
1382}
1383
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001384static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001385{
1386 struct pending_cmd *cmd;
1387
1388 BT_DBG(" %u", status);
1389
1390 cmd = find_pairing(conn);
1391 if (!cmd) {
1392 BT_DBG("Unable to find a pending command");
1393 return;
1394 }
1395
1396 if (conn->type == LE_LINK)
1397 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1398 status ? 0 : 1);
1399 else
1400 pairing_complete(cmd, status);
1401}
1402
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001403static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001404{
1405 struct pending_cmd *cmd;
1406
1407 BT_DBG("conn: %p %u", conn, status);
1408
1409 cmd = find_pairing(conn);
1410 if (!cmd) {
1411 BT_DBG("Unable to find a pending command");
1412 return;
1413 }
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001414 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001415}
1416
1417static void discovery_terminated(struct pending_cmd *cmd, void *data)
1418{
1419 struct mgmt_mode ev = {0};
1420 struct disco_interleave *ilp = cmd->param;
1421
1422 BT_DBG("");
1423 del_timer_sync(&ilp->le_timer);
1424 del_timer_sync(&ilp->timer);
1425 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1426
1427 list_del(&cmd->list);
1428
1429 mgmt_pending_free(cmd);
1430}
1431
Szymon Janc4e51eae2011-02-25 19:05:48 +01001432static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001433{
1434 struct hci_dev *hdev;
1435 struct mgmt_cp_pair_device *cp;
1436 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001437 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001438 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001439 int err;
1440
1441 BT_DBG("");
1442
Brian Gix64bd5302011-09-08 11:35:48 -07001443 cp = (void *) data;
1444
1445 if (len != sizeof(*cp))
1446 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1447
Szymon Janc4e51eae2011-02-25 19:05:48 +01001448 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001449
Johan Hedberge9a416b2011-02-19 12:05:56 -03001450 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001454
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301455 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1456 io_cap = cp->io_cap;
1457 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001458 sec_level = BT_SECURITY_MEDIUM;
1459 auth_type = HCI_AT_DEDICATED_BONDING;
1460 } else {
1461 sec_level = BT_SECURITY_HIGH;
1462 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1463 }
1464
Brian Gixa68668b2011-08-11 15:49:36 -07001465 if (hci_find_adv_entry(hdev, &cp->bdaddr)) {
1466 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1467 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001468 } else {
1469 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1470 if (io_cap == 0x04)
1471 io_cap = 0x01;
1472 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1473 auth_type);
1474 }
1475
Ville Tervo30e76272011-02-22 16:10:53 -03001476 if (IS_ERR(conn)) {
1477 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001478 goto unlock;
1479 }
1480
1481 if (conn->connect_cfm_cb) {
1482 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001483 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001484 goto unlock;
1485 }
1486
Szymon Janc4e51eae2011-02-25 19:05:48 +01001487 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001488 if (!cmd) {
1489 err = -ENOMEM;
1490 hci_conn_put(conn);
1491 goto unlock;
1492 }
1493
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001494 conn->connect_cfm_cb = pairing_connect_complete_cb;
1495 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001496 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001497 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001498 cmd->user_data = conn;
1499
1500 if (conn->state == BT_CONNECTED &&
1501 hci_conn_security(conn, sec_level, auth_type))
1502 pairing_complete(cmd, 0);
1503
1504 err = 0;
1505
1506unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508 hci_dev_put(hdev);
1509
1510 return err;
1511}
1512
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001514 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001515{
1516 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001517 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001518 struct pending_cmd *cmd;
1519 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001520 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001521 int err;
1522
Brian Gixa68668b2011-08-11 15:49:36 -07001523 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001524
Brian Gixa68668b2011-08-11 15:49:36 -07001525 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001526 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001527 else
1528 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001529
Brian Gixa68668b2011-08-11 15:49:36 -07001530 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001531 return cmd_status(sk, index, mgmt_op, EINVAL);
1532
Szymon Janc4e51eae2011-02-25 19:05:48 +01001533 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001534 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001535 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001538
Johan Hedberga5c29682011-02-19 12:05:57 -03001539 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001540 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001541 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001542 }
1543
Brian Gixa68668b2011-08-11 15:49:36 -07001544 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1545 if (le_conn) {
1546 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1547 goto done;
1548 }
1549 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1550 "Reject" : "Accept");
1551
Szymon Janc4e51eae2011-02-25 19:05:48 +01001552 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001553 if (!cmd) {
1554 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001555 goto done;
1556 }
1557
1558 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1559 if (err < 0)
1560 mgmt_pending_remove(cmd);
1561
1562done:
1563 hci_dev_unlock(hdev);
1564 hci_dev_put(hdev);
1565
1566 return err;
1567}
1568
1569static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1570 u16 len)
1571{
1572 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1573 struct hci_cp_remote_name_req hci_cp;
1574 struct hci_dev *hdev;
1575 struct pending_cmd *cmd;
1576 int err;
1577
1578 BT_DBG("");
1579
1580 if (len != sizeof(*mgmt_cp))
1581 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1582
1583 hdev = hci_dev_get(index);
1584 if (!hdev)
1585 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1586
1587 hci_dev_lock(hdev);
1588
1589 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1590 if (!cmd) {
1591 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001592 goto failed;
1593 }
1594
Brian Gixa68668b2011-08-11 15:49:36 -07001595 memset(&hci_cp, 0, sizeof(hci_cp));
1596 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1597 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1598 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001599 if (err < 0)
1600 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001601
1602failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001604 hci_dev_put(hdev);
1605
1606 return err;
1607}
1608
Johan Hedbergb312b1612011-03-16 14:29:37 +02001609static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1610 u16 len)
1611{
1612 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1613 struct hci_cp_write_local_name hci_cp;
1614 struct hci_dev *hdev;
1615 struct pending_cmd *cmd;
1616 int err;
1617
1618 BT_DBG("");
1619
1620 if (len != sizeof(*mgmt_cp))
1621 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1622
1623 hdev = hci_dev_get(index);
1624 if (!hdev)
1625 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001628
1629 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1630 if (!cmd) {
1631 err = -ENOMEM;
1632 goto failed;
1633 }
1634
1635 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1636 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1637 &hci_cp);
1638 if (err < 0)
1639 mgmt_pending_remove(cmd);
1640
1641failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001643 hci_dev_put(hdev);
1644
1645 return err;
1646}
1647
Brian Gixa68668b2011-08-11 15:49:36 -07001648static void discovery_rsp(struct pending_cmd *cmd, void *data)
1649{
1650 struct mgmt_mode ev;
1651
1652 BT_DBG("");
1653 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1654 ev.val = 1;
1655 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1656 } else {
1657 ev.val = 0;
1658 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1659 NULL, 0);
1660 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1661 struct disco_interleave *ilp = cmd->param;
1662
1663 del_timer_sync(&ilp->le_timer);
1664 del_timer_sync(&ilp->timer);
1665 }
1666 }
1667
1668 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1669
1670 list_del(&cmd->list);
1671
1672 mgmt_pending_free(cmd);
1673}
1674
1675void mgmt_inquiry_started(u16 index)
1676{
1677 BT_DBG("");
1678 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1679 discovery_rsp, NULL);
1680}
1681
1682void mgmt_inquiry_complete_evt(u16 index, u8 status)
1683{
1684 struct hci_dev *hdev;
1685 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1686 struct pending_cmd *cmd;
1687 int err = -1;
1688
1689 BT_DBG("");
1690
1691 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001692
1693 if (hdev)
1694 hci_dev_lock(hdev);
1695
Brian Gixa68668b2011-08-11 15:49:36 -07001696 if (!hdev || !lmp_le_capable(hdev)) {
1697 struct mgmt_mode cp = {0};
1698
1699 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1700 discovery_terminated, NULL);
1701
1702 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001703
Brian Gix64bd5302011-09-08 11:35:48 -07001704 if (hdev)
1705 goto done;
1706 else
1707 return;
1708 }
Brian Gixa68668b2011-08-11 15:49:36 -07001709
1710 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1711 if (cmd && cmd->param) {
1712 struct disco_interleave *ilp = cmd->param;
1713
1714 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1715 sizeof(le_cp), &le_cp);
1716 if (err >= 0) {
1717 mod_timer(&ilp->le_timer, jiffies +
1718 msecs_to_jiffies(ilp->int_phase * 1000));
1719 ilp->mode = SCAN_LE;
1720 } else
1721 ilp->mode = SCAN_IDLE;
1722 }
1723
1724 if (err < 0)
1725 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1726 discovery_terminated, NULL);
1727
Brian Gix64bd5302011-09-08 11:35:48 -07001728done:
Brian Gixa68668b2011-08-11 15:49:36 -07001729 hci_dev_unlock(hdev);
1730 hci_dev_put(hdev);
1731}
1732
1733static void disco_to(unsigned long data)
1734{
1735 struct disco_interleave *ilp = (void *)data;
1736 struct hci_dev *hdev;
1737 struct pending_cmd *cmd;
1738
1739 BT_DBG("hci%d", ilp->index);
1740
1741 del_timer_sync(&ilp->le_timer);
1742 hdev = hci_dev_get(ilp->index);
1743
1744 if (hdev) {
1745 hci_dev_lock(hdev);
1746
1747 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1748
1749 if (ilp->mode != SCAN_IDLE) {
1750 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1751
1752 if (ilp->mode == SCAN_LE)
1753 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1754 sizeof(le_cp), &le_cp);
1755 else
1756 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1757 0, NULL);
1758
1759 ilp->mode = SCAN_IDLE;
1760 }
1761
1762 if (cmd) {
1763 struct mgmt_mode cp = {0};
1764
1765 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1766 sizeof(cp), NULL);
1767 mgmt_pending_remove(cmd);
1768 }
1769
1770 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001771 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001772 }
1773}
1774
1775static void disco_le_to(unsigned long data)
1776{
1777 struct disco_interleave *ilp = (void *)data;
1778 struct hci_dev *hdev;
1779 struct pending_cmd *cmd;
1780 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1781
1782 BT_DBG("hci%d", ilp->index);
1783
1784 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001785
1786 if (hdev) {
1787 hci_dev_lock(hdev);
1788
1789 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1790
1791 if (ilp->mode == SCAN_LE)
1792 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1793 sizeof(le_cp), &le_cp);
1794
1795 /* re-start BR scan */
1796 if (cmd) {
1797 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1798 ilp->int_phase *= 2;
1799 ilp->int_count = 0;
1800 cp.num_rsp = (u8) ilp->int_phase;
1801 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1802 ilp->mode = SCAN_BR;
1803 } else
1804 ilp->mode = SCAN_IDLE;
1805
1806 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001807 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001808 }
1809}
1810
1811static int start_discovery(struct sock *sk, u16 index)
1812{
1813 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1814 struct hci_dev *hdev;
1815 struct pending_cmd *cmd;
1816 int err;
1817
1818 BT_DBG("");
1819
1820 hdev = hci_dev_get(index);
1821 if (!hdev)
1822 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1823
1824 hci_dev_lock(hdev);
1825
1826 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1827 if (!cmd) {
1828 err = -ENOMEM;
1829 goto failed;
1830 }
1831
1832 /* If LE Capable, we will alternate between BR/EDR and LE */
1833 if (lmp_le_capable(hdev)) {
1834 struct hci_cp_le_set_scan_parameters le_cp;
1835
1836 /* Shorten BR scan params */
1837 cp.num_rsp = 1;
1838 cp.length /= 2;
1839
1840 /* Setup LE scan params */
1841 memset(&le_cp, 0, sizeof(le_cp));
1842 le_cp.type = 0x01; /* Active scanning */
1843 /* The recommended value for scan interval and window is
1844 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1845 le_cp.interval = cpu_to_le16(0x0012);
1846 le_cp.window = cpu_to_le16(0x0012);
1847 le_cp.own_bdaddr_type = 0; /* Public address */
1848 le_cp.filter = 0; /* Accept all adv packets */
1849
1850 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1851 sizeof(le_cp), &le_cp);
1852 }
1853
1854 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1855
1856 if (err < 0)
1857 mgmt_pending_remove(cmd);
1858 else if (lmp_le_capable(hdev)) {
1859 struct disco_interleave il, *ilp;
1860
1861 il.int_phase = 1;
1862 il.int_count = 0;
1863 il.index = index;
1864 il.mode = SCAN_BR;
1865 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1866 sizeof(struct disco_interleave));
1867 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1868 if (cmd) {
1869 ilp = cmd->param;
1870 setup_timer(&ilp->le_timer, disco_le_to,
1871 (unsigned long) ilp);
1872 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1873 mod_timer(&ilp->timer,
1874 jiffies + msecs_to_jiffies(20000));
1875 }
1876 }
1877
1878failed:
1879 hci_dev_unlock(hdev);
1880 hci_dev_put(hdev);
1881
1882 return err;
1883}
1884
1885static int stop_discovery(struct sock *sk, u16 index)
1886{
1887 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1888 struct mgmt_mode mode_cp = {0};
1889 struct disco_interleave *ilp = NULL;
1890 struct hci_dev *hdev;
1891 struct pending_cmd *cmd = NULL;
1892 int err = -EPERM;
1893
1894 BT_DBG("");
1895
1896 hdev = hci_dev_get(index);
1897 if (!hdev)
1898 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1899
1900 hci_dev_lock(hdev);
1901
1902 if (lmp_le_capable(hdev)) {
1903 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1904 if (!cmd) {
1905 err = -ENOMEM;
1906 goto failed;
1907 }
1908
1909 ilp = cmd->param;
1910 }
1911
1912 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1913 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1914 sizeof(le_cp), &le_cp);
1915
1916 if (err < 0) {
1917 if (!ilp || (ilp->mode == SCAN_BR))
1918 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1919 0, NULL);
1920 }
1921
1922 if (ilp) {
1923 ilp->mode = SCAN_IDLE;
1924 del_timer_sync(&ilp->le_timer);
1925 del_timer_sync(&ilp->timer);
1926 }
1927
1928 if (err < 0 && cmd)
1929 mgmt_pending_remove(cmd);
1930
1931 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1932
1933failed:
1934 hci_dev_unlock(hdev);
1935 hci_dev_put(hdev);
1936
1937 if (err < 0)
1938 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1939 else
1940 return err;
1941}
1942
Szymon Jancc35938b2011-03-22 13:12:21 +01001943static int read_local_oob_data(struct sock *sk, u16 index)
1944{
1945 struct hci_dev *hdev;
1946 struct pending_cmd *cmd;
1947 int err;
1948
1949 BT_DBG("hci%u", index);
1950
1951 hdev = hci_dev_get(index);
1952 if (!hdev)
1953 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1954 ENODEV);
1955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001957
1958 if (!test_bit(HCI_UP, &hdev->flags)) {
1959 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1960 ENETDOWN);
1961 goto unlock;
1962 }
1963
1964 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1965 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1966 EOPNOTSUPP);
1967 goto unlock;
1968 }
1969
1970 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1971 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1972 goto unlock;
1973 }
1974
1975 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1976 if (!cmd) {
1977 err = -ENOMEM;
1978 goto unlock;
1979 }
1980
1981 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1982 if (err < 0)
1983 mgmt_pending_remove(cmd);
1984
1985unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001987 hci_dev_put(hdev);
1988
1989 return err;
1990}
1991
Szymon Janc2763eda2011-03-22 13:12:22 +01001992static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1993 u16 len)
1994{
1995 struct hci_dev *hdev;
1996 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1997 int err;
1998
1999 BT_DBG("hci%u ", index);
2000
2001 if (len != sizeof(*cp))
2002 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2003 EINVAL);
2004
2005 hdev = hci_dev_get(index);
2006 if (!hdev)
2007 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2008 ENODEV);
2009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002011
2012 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2013 cp->randomizer);
2014 if (err < 0)
2015 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2016 else
2017 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2018 0);
2019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002021 hci_dev_put(hdev);
2022
2023 return err;
2024}
2025
2026static int remove_remote_oob_data(struct sock *sk, u16 index,
2027 unsigned char *data, u16 len)
2028{
2029 struct hci_dev *hdev;
2030 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2031 int err;
2032
2033 BT_DBG("hci%u ", index);
2034
2035 if (len != sizeof(*cp))
2036 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2037 EINVAL);
2038
2039 hdev = hci_dev_get(index);
2040 if (!hdev)
2041 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2042 ENODEV);
2043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002045
2046 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2047 if (err < 0)
2048 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2049 -err);
2050 else
2051 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2052 NULL, 0);
2053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002055 hci_dev_put(hdev);
2056
2057 return err;
2058}
2059
Johan Hedberg03811012010-12-08 00:21:06 +02002060int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2061{
2062 unsigned char *buf;
2063 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002064 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002065 int err;
2066
2067 BT_DBG("got %zu bytes", msglen);
2068
2069 if (msglen < sizeof(*hdr))
2070 return -EINVAL;
2071
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002072 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002073 if (!buf)
2074 return -ENOMEM;
2075
2076 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2077 err = -EFAULT;
2078 goto done;
2079 }
2080
2081 hdr = (struct mgmt_hdr *) buf;
2082 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002083 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002084 len = get_unaligned_le16(&hdr->len);
2085
2086 if (len != msglen - sizeof(*hdr)) {
2087 err = -EINVAL;
2088 goto done;
2089 }
2090
Brian Gixa68668b2011-08-11 15:49:36 -07002091 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002092 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002093 case MGMT_OP_READ_VERSION:
2094 err = read_version(sk);
2095 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002096 case MGMT_OP_READ_INDEX_LIST:
2097 err = read_index_list(sk);
2098 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002099 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002100 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002101 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002102 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002104 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002105 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002106 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002107 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002108 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002109 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002110 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002111 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002113 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002114 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002116 break;
2117 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002118 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002120 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002122 break;
2123 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002124 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002125 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002126 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002127 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002128 break;
2129 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002130 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002131 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002132 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002133 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002134 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002135 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002136 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002137 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002139 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 break;
2141 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002142 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002144 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002146 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002147 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002148 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002150 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002151 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002152 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002153 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2154 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002155 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002156 case MGMT_OP_SET_LOCAL_NAME:
2157 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2158 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002159 case MGMT_OP_START_DISCOVERY:
2160 err = start_discovery(sk, index);
2161 break;
2162 case MGMT_OP_STOP_DISCOVERY:
2163 err = stop_discovery(sk, index);
2164 break;
2165 case MGMT_OP_RESOLVE_NAME:
2166 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2167 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 case MGMT_OP_READ_LOCAL_OOB_DATA:
2169 err = read_local_oob_data(sk, index);
2170 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002171 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2172 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2173 break;
2174 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2175 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2176 len);
2177 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178
Johan Hedberg03811012010-12-08 00:21:06 +02002179 default:
2180 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002181 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002182 break;
2183 }
2184
Johan Hedberge41d8b42010-12-13 21:07:03 +02002185 if (err < 0)
2186 goto done;
2187
Johan Hedberg03811012010-12-08 00:21:06 +02002188 err = msglen;
2189
2190done:
2191 kfree(buf);
2192 return err;
2193}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002194
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002195int mgmt_index_added(u16 index)
2196{
Brian Gixa68668b2011-08-11 15:49:36 -07002197 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002198 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002199}
2200
2201int mgmt_index_removed(u16 index)
2202{
Brian Gixa68668b2011-08-11 15:49:36 -07002203 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002204 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002205}
2206
Johan Hedberg73f22f62010-12-29 16:00:25 +02002207struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002208 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002209 struct sock *sk;
2210};
2211
Johan Hedberg72a734e2010-12-30 00:38:22 +02002212static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002213{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002214 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002215 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002216
Johan Hedberg72a734e2010-12-30 00:38:22 +02002217 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002218 return;
2219
Johan Hedberg053f0212011-01-26 13:07:10 +02002220 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002221
2222 list_del(&cmd->list);
2223
2224 if (match->sk == NULL) {
2225 match->sk = cmd->sk;
2226 sock_hold(match->sk);
2227 }
2228
2229 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002230}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002231
2232int mgmt_powered(u16 index, u8 powered)
2233{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002234 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002235 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002236 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002237
Brian Gixa68668b2011-08-11 15:49:36 -07002238 BT_DBG("hci%u %d", index, powered);
2239
Johan Hedberg72a734e2010-12-30 00:38:22 +02002240 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002241
Johan Hedberg72a734e2010-12-30 00:38:22 +02002242 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002243
Szymon Janc4e51eae2011-02-25 19:05:48 +01002244 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002245
2246 if (match.sk)
2247 sock_put(match.sk);
2248
2249 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002250}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002251
Johan Hedberg73f22f62010-12-29 16:00:25 +02002252int mgmt_discoverable(u16 index, u8 discoverable)
2253{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002254 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002255 struct cmd_lookup match = { discoverable, NULL };
2256 int ret;
2257
Szymon Jancb8534e02011-03-01 16:55:34 +01002258 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002259
Johan Hedberg72a734e2010-12-30 00:38:22 +02002260 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002261
Szymon Janc4e51eae2011-02-25 19:05:48 +01002262 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2263 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002264
2265 if (match.sk)
2266 sock_put(match.sk);
2267
2268 return ret;
2269}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002270
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002271int mgmt_connectable(u16 index, u8 connectable)
2272{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002273 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002274 struct cmd_lookup match = { connectable, NULL };
2275 int ret;
2276
Johan Hedberg72a734e2010-12-30 00:38:22 +02002277 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002278
Johan Hedberg72a734e2010-12-30 00:38:22 +02002279 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002280
Szymon Janc4e51eae2011-02-25 19:05:48 +01002281 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002282
2283 if (match.sk)
2284 sock_put(match.sk);
2285
2286 return ret;
2287}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002288
Brian Gixa68668b2011-08-11 15:49:36 -07002289int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002290{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002291 struct mgmt_ev_new_key *ev;
2292 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002293
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002294 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2295 ev = kzalloc(total, GFP_ATOMIC);
2296 if (!ev)
2297 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002298
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002299 bacpy(&ev->key.bdaddr, &key->bdaddr);
2300 ev->key.type = key->type;
2301 memcpy(ev->key.val, key->val, 16);
2302 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002303 ev->key.auth = key->auth;
2304 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002305 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002306
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002307 memcpy(ev->key.data, key->data, key->dlen);
2308
2309 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2310
2311 kfree(ev);
2312
2313 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002314}
Johan Hedbergf7520542011-01-20 12:34:39 +02002315
Brian Gix2e2f50d2011-09-13 12:36:04 -07002316int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002317{
2318 struct mgmt_ev_connected ev;
2319
Johan Hedbergf7520542011-01-20 12:34:39 +02002320 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002321 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002322
Szymon Janc4e51eae2011-02-25 19:05:48 +01002323 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002324}
2325
Johan Hedberg8962ee72011-01-20 12:40:27 +02002326static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2327{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002328 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002329 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002330 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331
Johan Hedberga38528f2011-01-22 06:46:43 +02002332 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002333
Szymon Janc4e51eae2011-02-25 19:05:48 +01002334 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335
2336 *sk = cmd->sk;
2337 sock_hold(*sk);
2338
Johan Hedberga664b5b2011-02-19 12:06:02 -03002339 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002340}
2341
Johan Hedbergf7520542011-01-20 12:34:39 +02002342int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2343{
2344 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002345 struct sock *sk = NULL;
2346 int err;
2347
2348 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002349
Johan Hedbergf7520542011-01-20 12:34:39 +02002350 bacpy(&ev.bdaddr, bdaddr);
2351
Szymon Janc4e51eae2011-02-25 19:05:48 +01002352 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002353
2354 if (sk)
2355 sock_put(sk);
2356
2357 return err;
2358}
2359
2360int mgmt_disconnect_failed(u16 index)
2361{
2362 struct pending_cmd *cmd;
2363 int err;
2364
2365 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2366 if (!cmd)
2367 return -ENOENT;
2368
Szymon Janc4e51eae2011-02-25 19:05:48 +01002369 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002370
Johan Hedberga664b5b2011-02-19 12:06:02 -03002371 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372
2373 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002374}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002375
2376int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2377{
2378 struct mgmt_ev_connect_failed ev;
2379
Johan Hedberg17d5c042011-01-22 06:09:08 +02002380 bacpy(&ev.bdaddr, bdaddr);
2381 ev.status = status;
2382
Szymon Janc4e51eae2011-02-25 19:05:48 +01002383 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002384}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387{
2388 struct mgmt_ev_pin_code_request ev;
2389
Brian Gixa68668b2011-08-11 15:49:36 -07002390 BT_DBG("hci%u", index);
2391
Johan Hedberg980e1a52011-01-22 06:10:07 +02002392 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002393 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002394
Szymon Janc4e51eae2011-02-25 19:05:48 +01002395 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2396 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002397}
2398
2399int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2400{
2401 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002402 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002403 int err;
2404
2405 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2406 if (!cmd)
2407 return -ENOENT;
2408
Johan Hedbergac56fb12011-02-19 12:05:59 -03002409 bacpy(&rp.bdaddr, bdaddr);
2410 rp.status = status;
2411
Szymon Janc4e51eae2011-02-25 19:05:48 +01002412 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2413 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002414
Johan Hedberga664b5b2011-02-19 12:06:02 -03002415 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002416
2417 return err;
2418}
2419
2420int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2421{
2422 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002423 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002424 int err;
2425
2426 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2427 if (!cmd)
2428 return -ENOENT;
2429
Johan Hedbergac56fb12011-02-19 12:05:59 -03002430 bacpy(&rp.bdaddr, bdaddr);
2431 rp.status = status;
2432
Szymon Janc4e51eae2011-02-25 19:05:48 +01002433 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2434 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002435
Johan Hedberga664b5b2011-02-19 12:06:02 -03002436 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002437
2438 return err;
2439}
Johan Hedberga5c29682011-02-19 12:05:57 -03002440
Brian Gixa68668b2011-08-11 15:49:36 -07002441int mgmt_user_confirm_request(u16 index, u8 event,
2442 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002443{
2444 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002445 struct hci_conn *conn = NULL;
2446 struct hci_dev *hdev;
2447 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2448
2449 BT_DBG("hci%u", index);
2450
2451 hdev = hci_dev_get(index);
2452
Brian Gix64bd5302011-09-08 11:35:48 -07002453 if (!hdev)
2454 return -ENODEV;
2455
Brian Gix64bd5302011-09-08 11:35:48 -07002456 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002457
2458 ev.auto_confirm = 0;
2459
2460 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2461 goto no_auto_confirm;
2462
2463 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2464 rem_cap = conn->remote_cap;
2465 loc_mitm = conn->auth_type & 0x01;
2466 rem_mitm = conn->remote_auth & 0x01;
2467
2468 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2469 goto no_auto_confirm;
2470
2471
2472 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2473 ev.auto_confirm = 1;
2474
2475no_auto_confirm:
2476 bacpy(&ev.bdaddr, bdaddr);
2477 ev.event = event;
2478 put_unaligned_le32(value, &ev.value);
2479
Brian Gix64bd5302011-09-08 11:35:48 -07002480 hci_dev_put(hdev);
2481
Brian Gixa68668b2011-08-11 15:49:36 -07002482 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2483 NULL);
2484}
2485
2486int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2487{
2488 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002489
2490 BT_DBG("hci%u", index);
2491
Johan Hedberga5c29682011-02-19 12:05:57 -03002492 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002493
Brian Gixa68668b2011-08-11 15:49:36 -07002494 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002495 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002496}
2497
2498static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2499 u8 opcode)
2500{
2501 struct pending_cmd *cmd;
2502 struct mgmt_rp_user_confirm_reply rp;
2503 int err;
2504
2505 cmd = mgmt_pending_find(opcode, index);
2506 if (!cmd)
2507 return -ENOENT;
2508
Johan Hedberga5c29682011-02-19 12:05:57 -03002509 bacpy(&rp.bdaddr, bdaddr);
2510 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002511 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002512
Johan Hedberga664b5b2011-02-19 12:06:02 -03002513 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002514
2515 return err;
2516}
2517
2518int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2519{
2520 return confirm_reply_complete(index, bdaddr, status,
2521 MGMT_OP_USER_CONFIRM_REPLY);
2522}
2523
Szymon Jancb8534e02011-03-01 16:55:34 +01002524int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002525{
2526 return confirm_reply_complete(index, bdaddr, status,
2527 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2528}
Johan Hedberg2a611692011-02-19 12:06:00 -03002529
2530int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2531{
2532 struct mgmt_ev_auth_failed ev;
2533
Johan Hedberg2a611692011-02-19 12:06:00 -03002534 bacpy(&ev.bdaddr, bdaddr);
2535 ev.status = status;
2536
Szymon Janc4e51eae2011-02-25 19:05:48 +01002537 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002538}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002539
2540int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2541{
2542 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002543 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002544 struct mgmt_cp_set_local_name ev;
2545 int err;
2546
2547 memset(&ev, 0, sizeof(ev));
2548 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2549
2550 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2551 if (!cmd)
2552 goto send_event;
2553
2554 if (status) {
2555 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2556 goto failed;
2557 }
2558
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002559 hdev = hci_dev_get(index);
2560 if (hdev) {
2561 hci_dev_lock_bh(hdev);
2562 update_eir(hdev);
2563 hci_dev_unlock_bh(hdev);
2564 hci_dev_put(hdev);
2565 }
2566
Johan Hedbergb312b1612011-03-16 14:29:37 +02002567 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2568 sizeof(ev));
2569 if (err < 0)
2570 goto failed;
2571
2572send_event:
2573 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2574 cmd ? cmd->sk : NULL);
2575
2576failed:
2577 if (cmd)
2578 mgmt_pending_remove(cmd);
2579 return err;
2580}
Szymon Jancc35938b2011-03-22 13:12:21 +01002581
2582int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2583 u8 status)
2584{
2585 struct pending_cmd *cmd;
2586 int err;
2587
2588 BT_DBG("hci%u status %u", index, status);
2589
2590 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2591 if (!cmd)
2592 return -ENOENT;
2593
2594 if (status) {
2595 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2596 EIO);
2597 } else {
2598 struct mgmt_rp_read_local_oob_data rp;
2599
2600 memcpy(rp.hash, hash, sizeof(rp.hash));
2601 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2602
2603 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2604 &rp, sizeof(rp));
2605 }
2606
2607 mgmt_pending_remove(cmd);
2608
2609 return err;
2610}
Johan Hedberge17acd42011-03-30 23:57:16 +03002611
Brian Gixa68668b2011-08-11 15:49:36 -07002612int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2613 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002614{
2615 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002616 struct pending_cmd *cmd;
2617 int err;
2618
2619 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002620
2621 memset(&ev, 0, sizeof(ev));
2622
2623 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002624 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002625 ev.type = type;
2626 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002627
Brian Gixa68668b2011-08-11 15:49:36 -07002628 if (dev_class)
2629 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002630
Brian Gixa68668b2011-08-11 15:49:36 -07002631 if (eir && eir_len)
2632 memcpy(ev.eir, eir, eir_len);
2633
2634 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2635
2636 if (err < 0)
2637 return err;
2638
2639 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2640 if (cmd) {
2641 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002642 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002643
2644 ilp->int_count++;
2645 if (hdev && ilp->int_count >= ilp->int_phase) {
2646 /* Inquiry scan for General Discovery LAP */
2647 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2648 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002649
Brian Gixa68668b2011-08-11 15:49:36 -07002650 ilp->int_phase *= 2;
2651 ilp->int_count = 0;
2652 if (ilp->mode == SCAN_LE) {
2653 /* cancel LE scan */
2654 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2655 sizeof(le_cp), &le_cp);
2656 /* start BR scan */
2657 cp.num_rsp = (u8) ilp->int_phase;
2658 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2659 sizeof(cp), &cp);
2660 ilp->mode = SCAN_BR;
2661 del_timer_sync(&ilp->le_timer);
2662 }
2663 }
Brian Gix64bd5302011-09-08 11:35:48 -07002664
2665 if (hdev)
2666 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002667 }
2668
2669 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002670}
Johan Hedberga88a9652011-03-30 13:18:12 +03002671
Brian Gixa68668b2011-08-11 15:49:36 -07002672
2673int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002674{
2675 struct mgmt_ev_remote_name ev;
2676
2677 memset(&ev, 0, sizeof(ev));
2678
2679 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002680 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002681 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2682
2683 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2684}