blob: 848a5152415aea864edefa36cf81d5ec3d13eb73 [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;
Brian Gixfdd38922011-09-28 16:23:48 -07001439 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001440 int err;
1441
1442 BT_DBG("");
1443
Brian Gix64bd5302011-09-08 11:35:48 -07001444 cp = (void *) data;
1445
1446 if (len != sizeof(*cp))
1447 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1448
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001450
Johan Hedberge9a416b2011-02-19 12:05:56 -03001451 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001455
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301456 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1457 io_cap = cp->io_cap;
1458 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001459 sec_level = BT_SECURITY_MEDIUM;
1460 auth_type = HCI_AT_DEDICATED_BONDING;
1461 } else {
1462 sec_level = BT_SECURITY_HIGH;
1463 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1464 }
1465
Brian Gixfdd38922011-09-28 16:23:48 -07001466 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1467 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001468 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1469 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001470 } else {
1471 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1472 if (io_cap == 0x04)
1473 io_cap = 0x01;
1474 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1475 auth_type);
1476 }
1477
Ville Tervo30e76272011-02-22 16:10:53 -03001478 if (IS_ERR(conn)) {
1479 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001480 goto unlock;
1481 }
1482
1483 if (conn->connect_cfm_cb) {
1484 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001485 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001486 goto unlock;
1487 }
1488
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490 if (!cmd) {
1491 err = -ENOMEM;
1492 hci_conn_put(conn);
1493 goto unlock;
1494 }
1495
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001496 conn->connect_cfm_cb = pairing_connect_complete_cb;
1497 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001498 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001499 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001500 cmd->user_data = conn;
1501
1502 if (conn->state == BT_CONNECTED &&
1503 hci_conn_security(conn, sec_level, auth_type))
1504 pairing_complete(cmd, 0);
1505
1506 err = 0;
1507
1508unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001510 hci_dev_put(hdev);
1511
1512 return err;
1513}
1514
Szymon Janc4e51eae2011-02-25 19:05:48 +01001515static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001516 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001517{
1518 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001519 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001520 struct pending_cmd *cmd;
1521 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001522 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001523 int err;
1524
Brian Gixa68668b2011-08-11 15:49:36 -07001525 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001526
Brian Gixa68668b2011-08-11 15:49:36 -07001527 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001528 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001529 else
1530 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001531
Brian Gixa68668b2011-08-11 15:49:36 -07001532 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001533 return cmd_status(sk, index, mgmt_op, EINVAL);
1534
Szymon Janc4e51eae2011-02-25 19:05:48 +01001535 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001536 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001537 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001540
Johan Hedberga5c29682011-02-19 12:05:57 -03001541 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001542 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001543 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001544 }
1545
Brian Gixa68668b2011-08-11 15:49:36 -07001546 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1547 if (le_conn) {
1548 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1549 goto done;
1550 }
1551 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1552 "Reject" : "Accept");
1553
Szymon Janc4e51eae2011-02-25 19:05:48 +01001554 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001555 if (!cmd) {
1556 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001557 goto done;
1558 }
1559
1560 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1561 if (err < 0)
1562 mgmt_pending_remove(cmd);
1563
1564done:
1565 hci_dev_unlock(hdev);
1566 hci_dev_put(hdev);
1567
1568 return err;
1569}
1570
1571static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1572 u16 len)
1573{
1574 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1575 struct hci_cp_remote_name_req hci_cp;
1576 struct hci_dev *hdev;
1577 struct pending_cmd *cmd;
1578 int err;
1579
1580 BT_DBG("");
1581
1582 if (len != sizeof(*mgmt_cp))
1583 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1584
1585 hdev = hci_dev_get(index);
1586 if (!hdev)
1587 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1588
1589 hci_dev_lock(hdev);
1590
1591 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1592 if (!cmd) {
1593 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001594 goto failed;
1595 }
1596
Brian Gixa68668b2011-08-11 15:49:36 -07001597 memset(&hci_cp, 0, sizeof(hci_cp));
1598 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1599 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1600 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001601 if (err < 0)
1602 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001603
1604failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001606 hci_dev_put(hdev);
1607
1608 return err;
1609}
1610
Johan Hedbergb312b1612011-03-16 14:29:37 +02001611static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1612 u16 len)
1613{
1614 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1615 struct hci_cp_write_local_name hci_cp;
1616 struct hci_dev *hdev;
1617 struct pending_cmd *cmd;
1618 int err;
1619
1620 BT_DBG("");
1621
1622 if (len != sizeof(*mgmt_cp))
1623 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1624
1625 hdev = hci_dev_get(index);
1626 if (!hdev)
1627 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001630
1631 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1632 if (!cmd) {
1633 err = -ENOMEM;
1634 goto failed;
1635 }
1636
1637 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1638 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1639 &hci_cp);
1640 if (err < 0)
1641 mgmt_pending_remove(cmd);
1642
1643failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001645 hci_dev_put(hdev);
1646
1647 return err;
1648}
1649
Brian Gixa68668b2011-08-11 15:49:36 -07001650static void discovery_rsp(struct pending_cmd *cmd, void *data)
1651{
1652 struct mgmt_mode ev;
1653
1654 BT_DBG("");
1655 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1656 ev.val = 1;
1657 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1658 } else {
1659 ev.val = 0;
1660 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1661 NULL, 0);
1662 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1663 struct disco_interleave *ilp = cmd->param;
1664
1665 del_timer_sync(&ilp->le_timer);
1666 del_timer_sync(&ilp->timer);
1667 }
1668 }
1669
1670 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1671
1672 list_del(&cmd->list);
1673
1674 mgmt_pending_free(cmd);
1675}
1676
1677void mgmt_inquiry_started(u16 index)
1678{
1679 BT_DBG("");
1680 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1681 discovery_rsp, NULL);
1682}
1683
1684void mgmt_inquiry_complete_evt(u16 index, u8 status)
1685{
1686 struct hci_dev *hdev;
1687 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1688 struct pending_cmd *cmd;
1689 int err = -1;
1690
1691 BT_DBG("");
1692
1693 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001694
1695 if (hdev)
1696 hci_dev_lock(hdev);
1697
Brian Gixa68668b2011-08-11 15:49:36 -07001698 if (!hdev || !lmp_le_capable(hdev)) {
1699 struct mgmt_mode cp = {0};
1700
1701 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1702 discovery_terminated, NULL);
1703
1704 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001705
Brian Gix64bd5302011-09-08 11:35:48 -07001706 if (hdev)
1707 goto done;
1708 else
1709 return;
1710 }
Brian Gixa68668b2011-08-11 15:49:36 -07001711
1712 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1713 if (cmd && cmd->param) {
1714 struct disco_interleave *ilp = cmd->param;
1715
1716 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1717 sizeof(le_cp), &le_cp);
1718 if (err >= 0) {
1719 mod_timer(&ilp->le_timer, jiffies +
1720 msecs_to_jiffies(ilp->int_phase * 1000));
1721 ilp->mode = SCAN_LE;
1722 } else
1723 ilp->mode = SCAN_IDLE;
1724 }
1725
1726 if (err < 0)
1727 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1728 discovery_terminated, NULL);
1729
Brian Gix64bd5302011-09-08 11:35:48 -07001730done:
Brian Gixa68668b2011-08-11 15:49:36 -07001731 hci_dev_unlock(hdev);
1732 hci_dev_put(hdev);
1733}
1734
1735static void disco_to(unsigned long data)
1736{
1737 struct disco_interleave *ilp = (void *)data;
1738 struct hci_dev *hdev;
1739 struct pending_cmd *cmd;
1740
1741 BT_DBG("hci%d", ilp->index);
1742
1743 del_timer_sync(&ilp->le_timer);
1744 hdev = hci_dev_get(ilp->index);
1745
1746 if (hdev) {
1747 hci_dev_lock(hdev);
1748
1749 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1750
1751 if (ilp->mode != SCAN_IDLE) {
1752 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1753
1754 if (ilp->mode == SCAN_LE)
1755 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1756 sizeof(le_cp), &le_cp);
1757 else
1758 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1759 0, NULL);
1760
1761 ilp->mode = SCAN_IDLE;
1762 }
1763
1764 if (cmd) {
1765 struct mgmt_mode cp = {0};
1766
1767 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1768 sizeof(cp), NULL);
1769 mgmt_pending_remove(cmd);
1770 }
1771
1772 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001773 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001774 }
1775}
1776
1777static void disco_le_to(unsigned long data)
1778{
1779 struct disco_interleave *ilp = (void *)data;
1780 struct hci_dev *hdev;
1781 struct pending_cmd *cmd;
1782 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1783
1784 BT_DBG("hci%d", ilp->index);
1785
1786 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001787
1788 if (hdev) {
1789 hci_dev_lock(hdev);
1790
1791 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1792
1793 if (ilp->mode == SCAN_LE)
1794 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1795 sizeof(le_cp), &le_cp);
1796
1797 /* re-start BR scan */
1798 if (cmd) {
1799 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1800 ilp->int_phase *= 2;
1801 ilp->int_count = 0;
1802 cp.num_rsp = (u8) ilp->int_phase;
1803 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1804 ilp->mode = SCAN_BR;
1805 } else
1806 ilp->mode = SCAN_IDLE;
1807
1808 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001809 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001810 }
1811}
1812
1813static int start_discovery(struct sock *sk, u16 index)
1814{
1815 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1816 struct hci_dev *hdev;
1817 struct pending_cmd *cmd;
1818 int err;
1819
1820 BT_DBG("");
1821
1822 hdev = hci_dev_get(index);
1823 if (!hdev)
1824 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1825
1826 hci_dev_lock(hdev);
1827
1828 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1829 if (!cmd) {
1830 err = -ENOMEM;
1831 goto failed;
1832 }
1833
1834 /* If LE Capable, we will alternate between BR/EDR and LE */
1835 if (lmp_le_capable(hdev)) {
1836 struct hci_cp_le_set_scan_parameters le_cp;
1837
1838 /* Shorten BR scan params */
1839 cp.num_rsp = 1;
1840 cp.length /= 2;
1841
1842 /* Setup LE scan params */
1843 memset(&le_cp, 0, sizeof(le_cp));
1844 le_cp.type = 0x01; /* Active scanning */
1845 /* The recommended value for scan interval and window is
1846 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1847 le_cp.interval = cpu_to_le16(0x0012);
1848 le_cp.window = cpu_to_le16(0x0012);
1849 le_cp.own_bdaddr_type = 0; /* Public address */
1850 le_cp.filter = 0; /* Accept all adv packets */
1851
1852 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1853 sizeof(le_cp), &le_cp);
1854 }
1855
1856 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1857
1858 if (err < 0)
1859 mgmt_pending_remove(cmd);
1860 else if (lmp_le_capable(hdev)) {
1861 struct disco_interleave il, *ilp;
1862
1863 il.int_phase = 1;
1864 il.int_count = 0;
1865 il.index = index;
1866 il.mode = SCAN_BR;
1867 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1868 sizeof(struct disco_interleave));
1869 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1870 if (cmd) {
1871 ilp = cmd->param;
1872 setup_timer(&ilp->le_timer, disco_le_to,
1873 (unsigned long) ilp);
1874 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1875 mod_timer(&ilp->timer,
1876 jiffies + msecs_to_jiffies(20000));
1877 }
1878 }
1879
1880failed:
1881 hci_dev_unlock(hdev);
1882 hci_dev_put(hdev);
1883
1884 return err;
1885}
1886
1887static int stop_discovery(struct sock *sk, u16 index)
1888{
1889 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1890 struct mgmt_mode mode_cp = {0};
1891 struct disco_interleave *ilp = NULL;
1892 struct hci_dev *hdev;
1893 struct pending_cmd *cmd = NULL;
1894 int err = -EPERM;
1895
1896 BT_DBG("");
1897
1898 hdev = hci_dev_get(index);
1899 if (!hdev)
1900 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1901
1902 hci_dev_lock(hdev);
1903
1904 if (lmp_le_capable(hdev)) {
1905 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1906 if (!cmd) {
1907 err = -ENOMEM;
1908 goto failed;
1909 }
1910
1911 ilp = cmd->param;
1912 }
1913
1914 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1915 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1916 sizeof(le_cp), &le_cp);
1917
1918 if (err < 0) {
1919 if (!ilp || (ilp->mode == SCAN_BR))
1920 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1921 0, NULL);
1922 }
1923
1924 if (ilp) {
1925 ilp->mode = SCAN_IDLE;
1926 del_timer_sync(&ilp->le_timer);
1927 del_timer_sync(&ilp->timer);
1928 }
1929
1930 if (err < 0 && cmd)
1931 mgmt_pending_remove(cmd);
1932
1933 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1934
1935failed:
1936 hci_dev_unlock(hdev);
1937 hci_dev_put(hdev);
1938
1939 if (err < 0)
1940 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1941 else
1942 return err;
1943}
1944
Szymon Jancc35938b2011-03-22 13:12:21 +01001945static int read_local_oob_data(struct sock *sk, u16 index)
1946{
1947 struct hci_dev *hdev;
1948 struct pending_cmd *cmd;
1949 int err;
1950
1951 BT_DBG("hci%u", index);
1952
1953 hdev = hci_dev_get(index);
1954 if (!hdev)
1955 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1956 ENODEV);
1957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001959
1960 if (!test_bit(HCI_UP, &hdev->flags)) {
1961 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1962 ENETDOWN);
1963 goto unlock;
1964 }
1965
1966 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1967 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1968 EOPNOTSUPP);
1969 goto unlock;
1970 }
1971
1972 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1973 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1974 goto unlock;
1975 }
1976
1977 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1978 if (!cmd) {
1979 err = -ENOMEM;
1980 goto unlock;
1981 }
1982
1983 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1984 if (err < 0)
1985 mgmt_pending_remove(cmd);
1986
1987unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001989 hci_dev_put(hdev);
1990
1991 return err;
1992}
1993
Szymon Janc2763eda2011-03-22 13:12:22 +01001994static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1995 u16 len)
1996{
1997 struct hci_dev *hdev;
1998 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1999 int err;
2000
2001 BT_DBG("hci%u ", index);
2002
2003 if (len != sizeof(*cp))
2004 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2005 EINVAL);
2006
2007 hdev = hci_dev_get(index);
2008 if (!hdev)
2009 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2010 ENODEV);
2011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002013
2014 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2015 cp->randomizer);
2016 if (err < 0)
2017 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2018 else
2019 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2020 0);
2021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002023 hci_dev_put(hdev);
2024
2025 return err;
2026}
2027
2028static int remove_remote_oob_data(struct sock *sk, u16 index,
2029 unsigned char *data, u16 len)
2030{
2031 struct hci_dev *hdev;
2032 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2033 int err;
2034
2035 BT_DBG("hci%u ", index);
2036
2037 if (len != sizeof(*cp))
2038 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2039 EINVAL);
2040
2041 hdev = hci_dev_get(index);
2042 if (!hdev)
2043 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2044 ENODEV);
2045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002047
2048 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2049 if (err < 0)
2050 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2051 -err);
2052 else
2053 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2054 NULL, 0);
2055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002057 hci_dev_put(hdev);
2058
2059 return err;
2060}
2061
Johan Hedberg03811012010-12-08 00:21:06 +02002062int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2063{
2064 unsigned char *buf;
2065 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002066 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002067 int err;
2068
2069 BT_DBG("got %zu bytes", msglen);
2070
2071 if (msglen < sizeof(*hdr))
2072 return -EINVAL;
2073
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002074 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002075 if (!buf)
2076 return -ENOMEM;
2077
2078 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2079 err = -EFAULT;
2080 goto done;
2081 }
2082
2083 hdr = (struct mgmt_hdr *) buf;
2084 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002085 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002086 len = get_unaligned_le16(&hdr->len);
2087
2088 if (len != msglen - sizeof(*hdr)) {
2089 err = -EINVAL;
2090 goto done;
2091 }
2092
Brian Gixa68668b2011-08-11 15:49:36 -07002093 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002094 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002095 case MGMT_OP_READ_VERSION:
2096 err = read_version(sk);
2097 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002098 case MGMT_OP_READ_INDEX_LIST:
2099 err = read_index_list(sk);
2100 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002101 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002103 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002104 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002105 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002106 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002107 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002108 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002109 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002110 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002111 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002112 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002113 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002114 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002115 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002116 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002118 break;
2119 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002121 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002122 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002123 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002124 break;
2125 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002126 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002127 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002128 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002129 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002130 break;
2131 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002132 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002133 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002134 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002135 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002136 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002137 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002138 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002139 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142 break;
2143 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002144 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002146 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002148 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002151 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002152 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002153 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002155 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2156 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002157 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002158 case MGMT_OP_SET_LOCAL_NAME:
2159 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2160 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002161 case MGMT_OP_START_DISCOVERY:
2162 err = start_discovery(sk, index);
2163 break;
2164 case MGMT_OP_STOP_DISCOVERY:
2165 err = stop_discovery(sk, index);
2166 break;
2167 case MGMT_OP_RESOLVE_NAME:
2168 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2169 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002170 case MGMT_OP_READ_LOCAL_OOB_DATA:
2171 err = read_local_oob_data(sk, index);
2172 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002173 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2174 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2175 break;
2176 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2177 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2178 len);
2179 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180
Johan Hedberg03811012010-12-08 00:21:06 +02002181 default:
2182 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002184 break;
2185 }
2186
Johan Hedberge41d8b42010-12-13 21:07:03 +02002187 if (err < 0)
2188 goto done;
2189
Johan Hedberg03811012010-12-08 00:21:06 +02002190 err = msglen;
2191
2192done:
2193 kfree(buf);
2194 return err;
2195}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002196
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002197int mgmt_index_added(u16 index)
2198{
Brian Gixa68668b2011-08-11 15:49:36 -07002199 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002200 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002201}
2202
2203int mgmt_index_removed(u16 index)
2204{
Brian Gixa68668b2011-08-11 15:49:36 -07002205 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002206 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002207}
2208
Johan Hedberg73f22f62010-12-29 16:00:25 +02002209struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002210 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002211 struct sock *sk;
2212};
2213
Johan Hedberg72a734e2010-12-30 00:38:22 +02002214static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002215{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002216 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002217 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002218
Johan Hedberg72a734e2010-12-30 00:38:22 +02002219 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002220 return;
2221
Johan Hedberg053f0212011-01-26 13:07:10 +02002222 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002223
2224 list_del(&cmd->list);
2225
2226 if (match->sk == NULL) {
2227 match->sk = cmd->sk;
2228 sock_hold(match->sk);
2229 }
2230
2231 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002232}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002233
2234int mgmt_powered(u16 index, u8 powered)
2235{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002236 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002237 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002238 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002239
Brian Gixa68668b2011-08-11 15:49:36 -07002240 BT_DBG("hci%u %d", index, powered);
2241
Johan Hedberg72a734e2010-12-30 00:38:22 +02002242 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002243
Johan Hedberg72a734e2010-12-30 00:38:22 +02002244 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002245
Szymon Janc4e51eae2011-02-25 19:05:48 +01002246 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002247
2248 if (match.sk)
2249 sock_put(match.sk);
2250
2251 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002252}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002253
Johan Hedberg73f22f62010-12-29 16:00:25 +02002254int mgmt_discoverable(u16 index, u8 discoverable)
2255{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002256 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002257 struct cmd_lookup match = { discoverable, NULL };
2258 int ret;
2259
Szymon Jancb8534e02011-03-01 16:55:34 +01002260 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002261
Johan Hedberg72a734e2010-12-30 00:38:22 +02002262 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002263
Szymon Janc4e51eae2011-02-25 19:05:48 +01002264 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2265 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002266
2267 if (match.sk)
2268 sock_put(match.sk);
2269
2270 return ret;
2271}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002272
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002273int mgmt_connectable(u16 index, u8 connectable)
2274{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002275 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002276 struct cmd_lookup match = { connectable, NULL };
2277 int ret;
2278
Johan Hedberg72a734e2010-12-30 00:38:22 +02002279 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002280
Johan Hedberg72a734e2010-12-30 00:38:22 +02002281 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002282
Szymon Janc4e51eae2011-02-25 19:05:48 +01002283 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002284
2285 if (match.sk)
2286 sock_put(match.sk);
2287
2288 return ret;
2289}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002290
Brian Gixa68668b2011-08-11 15:49:36 -07002291int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002292{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002293 struct mgmt_ev_new_key *ev;
2294 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002295
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002296 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2297 ev = kzalloc(total, GFP_ATOMIC);
2298 if (!ev)
2299 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002300
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002301 bacpy(&ev->key.bdaddr, &key->bdaddr);
2302 ev->key.type = key->type;
2303 memcpy(ev->key.val, key->val, 16);
2304 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002305 ev->key.auth = key->auth;
2306 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002307 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002308
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002309 memcpy(ev->key.data, key->data, key->dlen);
2310
2311 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2312
2313 kfree(ev);
2314
2315 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002316}
Johan Hedbergf7520542011-01-20 12:34:39 +02002317
Brian Gix2e2f50d2011-09-13 12:36:04 -07002318int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002319{
2320 struct mgmt_ev_connected ev;
2321
Johan Hedbergf7520542011-01-20 12:34:39 +02002322 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002323 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002324
Szymon Janc4e51eae2011-02-25 19:05:48 +01002325 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002326}
2327
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2329{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002330 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002332 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002333
Johan Hedberga38528f2011-01-22 06:46:43 +02002334 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335
Szymon Janc4e51eae2011-02-25 19:05:48 +01002336 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002337
2338 *sk = cmd->sk;
2339 sock_hold(*sk);
2340
Johan Hedberga664b5b2011-02-19 12:06:02 -03002341 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002342}
2343
Johan Hedbergf7520542011-01-20 12:34:39 +02002344int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2345{
2346 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002347 struct sock *sk = NULL;
2348 int err;
2349
2350 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002351
Johan Hedbergf7520542011-01-20 12:34:39 +02002352 bacpy(&ev.bdaddr, bdaddr);
2353
Szymon Janc4e51eae2011-02-25 19:05:48 +01002354 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002355
2356 if (sk)
2357 sock_put(sk);
2358
2359 return err;
2360}
2361
2362int mgmt_disconnect_failed(u16 index)
2363{
2364 struct pending_cmd *cmd;
2365 int err;
2366
2367 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2368 if (!cmd)
2369 return -ENOENT;
2370
Szymon Janc4e51eae2011-02-25 19:05:48 +01002371 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372
Johan Hedberga664b5b2011-02-19 12:06:02 -03002373 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002374
2375 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002376}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002377
2378int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2379{
2380 struct mgmt_ev_connect_failed ev;
2381
Johan Hedberg17d5c042011-01-22 06:09:08 +02002382 bacpy(&ev.bdaddr, bdaddr);
2383 ev.status = status;
2384
Szymon Janc4e51eae2011-02-25 19:05:48 +01002385 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002386}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002389{
2390 struct mgmt_ev_pin_code_request ev;
2391
Brian Gixa68668b2011-08-11 15:49:36 -07002392 BT_DBG("hci%u", index);
2393
Johan Hedberg980e1a52011-01-22 06:10:07 +02002394 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002395 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002396
Szymon Janc4e51eae2011-02-25 19:05:48 +01002397 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2398 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002399}
2400
2401int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2402{
2403 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002404 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002405 int err;
2406
2407 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2408 if (!cmd)
2409 return -ENOENT;
2410
Johan Hedbergac56fb12011-02-19 12:05:59 -03002411 bacpy(&rp.bdaddr, bdaddr);
2412 rp.status = status;
2413
Szymon Janc4e51eae2011-02-25 19:05:48 +01002414 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2415 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002416
Johan Hedberga664b5b2011-02-19 12:06:02 -03002417 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002418
2419 return err;
2420}
2421
2422int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2423{
2424 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002425 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002426 int err;
2427
2428 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2429 if (!cmd)
2430 return -ENOENT;
2431
Johan Hedbergac56fb12011-02-19 12:05:59 -03002432 bacpy(&rp.bdaddr, bdaddr);
2433 rp.status = status;
2434
Szymon Janc4e51eae2011-02-25 19:05:48 +01002435 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2436 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002437
Johan Hedberga664b5b2011-02-19 12:06:02 -03002438 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002439
2440 return err;
2441}
Johan Hedberga5c29682011-02-19 12:05:57 -03002442
Brian Gixa68668b2011-08-11 15:49:36 -07002443int mgmt_user_confirm_request(u16 index, u8 event,
2444 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002445{
2446 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002447 struct hci_conn *conn = NULL;
2448 struct hci_dev *hdev;
2449 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2450
2451 BT_DBG("hci%u", index);
2452
2453 hdev = hci_dev_get(index);
2454
Brian Gix64bd5302011-09-08 11:35:48 -07002455 if (!hdev)
2456 return -ENODEV;
2457
Brian Gix64bd5302011-09-08 11:35:48 -07002458 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002459
2460 ev.auto_confirm = 0;
2461
2462 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2463 goto no_auto_confirm;
2464
2465 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2466 rem_cap = conn->remote_cap;
2467 loc_mitm = conn->auth_type & 0x01;
2468 rem_mitm = conn->remote_auth & 0x01;
2469
2470 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2471 goto no_auto_confirm;
2472
2473
2474 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2475 ev.auto_confirm = 1;
2476
2477no_auto_confirm:
2478 bacpy(&ev.bdaddr, bdaddr);
2479 ev.event = event;
2480 put_unaligned_le32(value, &ev.value);
2481
Brian Gix64bd5302011-09-08 11:35:48 -07002482 hci_dev_put(hdev);
2483
Brian Gixa68668b2011-08-11 15:49:36 -07002484 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2485 NULL);
2486}
2487
2488int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2489{
2490 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002491
2492 BT_DBG("hci%u", index);
2493
Johan Hedberga5c29682011-02-19 12:05:57 -03002494 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002495
Brian Gixa68668b2011-08-11 15:49:36 -07002496 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002497 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002498}
2499
2500static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2501 u8 opcode)
2502{
2503 struct pending_cmd *cmd;
2504 struct mgmt_rp_user_confirm_reply rp;
2505 int err;
2506
2507 cmd = mgmt_pending_find(opcode, index);
2508 if (!cmd)
2509 return -ENOENT;
2510
Johan Hedberga5c29682011-02-19 12:05:57 -03002511 bacpy(&rp.bdaddr, bdaddr);
2512 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002513 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002514
Johan Hedberga664b5b2011-02-19 12:06:02 -03002515 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002516
2517 return err;
2518}
2519
2520int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2521{
2522 return confirm_reply_complete(index, bdaddr, status,
2523 MGMT_OP_USER_CONFIRM_REPLY);
2524}
2525
Szymon Jancb8534e02011-03-01 16:55:34 +01002526int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002527{
2528 return confirm_reply_complete(index, bdaddr, status,
2529 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2530}
Johan Hedberg2a611692011-02-19 12:06:00 -03002531
2532int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2533{
2534 struct mgmt_ev_auth_failed ev;
2535
Johan Hedberg2a611692011-02-19 12:06:00 -03002536 bacpy(&ev.bdaddr, bdaddr);
2537 ev.status = status;
2538
Szymon Janc4e51eae2011-02-25 19:05:48 +01002539 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002540}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002541
2542int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2543{
2544 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002545 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002546 struct mgmt_cp_set_local_name ev;
2547 int err;
2548
2549 memset(&ev, 0, sizeof(ev));
2550 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2551
2552 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2553 if (!cmd)
2554 goto send_event;
2555
2556 if (status) {
2557 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2558 goto failed;
2559 }
2560
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002561 hdev = hci_dev_get(index);
2562 if (hdev) {
2563 hci_dev_lock_bh(hdev);
2564 update_eir(hdev);
2565 hci_dev_unlock_bh(hdev);
2566 hci_dev_put(hdev);
2567 }
2568
Johan Hedbergb312b1612011-03-16 14:29:37 +02002569 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2570 sizeof(ev));
2571 if (err < 0)
2572 goto failed;
2573
2574send_event:
2575 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2576 cmd ? cmd->sk : NULL);
2577
2578failed:
2579 if (cmd)
2580 mgmt_pending_remove(cmd);
2581 return err;
2582}
Szymon Jancc35938b2011-03-22 13:12:21 +01002583
2584int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2585 u8 status)
2586{
2587 struct pending_cmd *cmd;
2588 int err;
2589
2590 BT_DBG("hci%u status %u", index, status);
2591
2592 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2593 if (!cmd)
2594 return -ENOENT;
2595
2596 if (status) {
2597 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2598 EIO);
2599 } else {
2600 struct mgmt_rp_read_local_oob_data rp;
2601
2602 memcpy(rp.hash, hash, sizeof(rp.hash));
2603 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2604
2605 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2606 &rp, sizeof(rp));
2607 }
2608
2609 mgmt_pending_remove(cmd);
2610
2611 return err;
2612}
Johan Hedberge17acd42011-03-30 23:57:16 +03002613
Brian Gixa68668b2011-08-11 15:49:36 -07002614int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2615 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002616{
2617 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002618 struct pending_cmd *cmd;
2619 int err;
2620
2621 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002622
2623 memset(&ev, 0, sizeof(ev));
2624
2625 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002626 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002627 ev.type = type;
2628 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002629
Brian Gixa68668b2011-08-11 15:49:36 -07002630 if (dev_class)
2631 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002632
Brian Gixa68668b2011-08-11 15:49:36 -07002633 if (eir && eir_len)
2634 memcpy(ev.eir, eir, eir_len);
2635
2636 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2637
2638 if (err < 0)
2639 return err;
2640
2641 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2642 if (cmd) {
2643 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002644 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002645
2646 ilp->int_count++;
2647 if (hdev && ilp->int_count >= ilp->int_phase) {
2648 /* Inquiry scan for General Discovery LAP */
2649 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2650 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002651
Brian Gixa68668b2011-08-11 15:49:36 -07002652 ilp->int_phase *= 2;
2653 ilp->int_count = 0;
2654 if (ilp->mode == SCAN_LE) {
2655 /* cancel LE scan */
2656 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2657 sizeof(le_cp), &le_cp);
2658 /* start BR scan */
2659 cp.num_rsp = (u8) ilp->int_phase;
2660 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2661 sizeof(cp), &cp);
2662 ilp->mode = SCAN_BR;
2663 del_timer_sync(&ilp->le_timer);
2664 }
2665 }
Brian Gix64bd5302011-09-08 11:35:48 -07002666
2667 if (hdev)
2668 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002669 }
2670
2671 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002672}
Johan Hedberga88a9652011-03-30 13:18:12 +03002673
Brian Gixa68668b2011-08-11 15:49:36 -07002674
2675int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002676{
2677 struct mgmt_ev_remote_name ev;
2678
2679 memset(&ev, 0, sizeof(ev));
2680
2681 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002682 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002683 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2684
2685 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2686}