blob: a328db965ccf62052add65ff3f1e3761a1bcfbf5 [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 Gix114f3a62011-09-27 14:02:20 -07001414
1415 if (status)
1416 pairing_complete(cmd, status);
1417
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001418 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001419}
1420
1421static void discovery_terminated(struct pending_cmd *cmd, void *data)
1422{
1423 struct mgmt_mode ev = {0};
1424 struct disco_interleave *ilp = cmd->param;
1425
1426 BT_DBG("");
1427 del_timer_sync(&ilp->le_timer);
1428 del_timer_sync(&ilp->timer);
1429 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1430
1431 list_del(&cmd->list);
1432
1433 mgmt_pending_free(cmd);
1434}
1435
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001437{
1438 struct hci_dev *hdev;
1439 struct mgmt_cp_pair_device *cp;
1440 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001441 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001442 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001443 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001444 int err;
1445
1446 BT_DBG("");
1447
Brian Gix64bd5302011-09-08 11:35:48 -07001448 cp = (void *) data;
1449
1450 if (len != sizeof(*cp))
1451 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001454
Johan Hedberge9a416b2011-02-19 12:05:56 -03001455 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001456 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001459
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301460 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1461 io_cap = cp->io_cap;
1462 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001463 sec_level = BT_SECURITY_MEDIUM;
1464 auth_type = HCI_AT_DEDICATED_BONDING;
1465 } else {
1466 sec_level = BT_SECURITY_HIGH;
1467 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1468 }
1469
Brian Gixfdd38922011-09-28 16:23:48 -07001470 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1471 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001472 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1473 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001474 } else {
1475 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1476 if (io_cap == 0x04)
1477 io_cap = 0x01;
1478 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1479 auth_type);
1480 }
1481
Ville Tervo30e76272011-02-22 16:10:53 -03001482 if (IS_ERR(conn)) {
1483 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001484 goto unlock;
1485 }
1486
1487 if (conn->connect_cfm_cb) {
1488 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490 goto unlock;
1491 }
1492
Szymon Janc4e51eae2011-02-25 19:05:48 +01001493 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494 if (!cmd) {
1495 err = -ENOMEM;
1496 hci_conn_put(conn);
1497 goto unlock;
1498 }
1499
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001500 conn->connect_cfm_cb = pairing_connect_complete_cb;
1501 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001502 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001503 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504 cmd->user_data = conn;
1505
1506 if (conn->state == BT_CONNECTED &&
1507 hci_conn_security(conn, sec_level, auth_type))
1508 pairing_complete(cmd, 0);
1509
1510 err = 0;
1511
1512unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514 hci_dev_put(hdev);
1515
1516 return err;
1517}
1518
Szymon Janc4e51eae2011-02-25 19:05:48 +01001519static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001520 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001521{
1522 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001523 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001524 struct pending_cmd *cmd;
1525 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001526 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001527 int err;
1528
Brian Gixa68668b2011-08-11 15:49:36 -07001529 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001530
Brian Gixa68668b2011-08-11 15:49:36 -07001531 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001532 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001533 else
1534 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001535
Brian Gixa68668b2011-08-11 15:49:36 -07001536 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001537 return cmd_status(sk, index, mgmt_op, EINVAL);
1538
Szymon Janc4e51eae2011-02-25 19:05:48 +01001539 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001540 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001541 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001544
Johan Hedberga5c29682011-02-19 12:05:57 -03001545 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001546 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001547 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001548 }
1549
Brian Gixa68668b2011-08-11 15:49:36 -07001550 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1551 if (le_conn) {
1552 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1553 goto done;
1554 }
1555 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1556 "Reject" : "Accept");
1557
Szymon Janc4e51eae2011-02-25 19:05:48 +01001558 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001559 if (!cmd) {
1560 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001561 goto done;
1562 }
1563
1564 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1565 if (err < 0)
1566 mgmt_pending_remove(cmd);
1567
1568done:
1569 hci_dev_unlock(hdev);
1570 hci_dev_put(hdev);
1571
1572 return err;
1573}
1574
1575static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1576 u16 len)
1577{
1578 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1579 struct hci_cp_remote_name_req hci_cp;
1580 struct hci_dev *hdev;
1581 struct pending_cmd *cmd;
1582 int err;
1583
1584 BT_DBG("");
1585
1586 if (len != sizeof(*mgmt_cp))
1587 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1588
1589 hdev = hci_dev_get(index);
1590 if (!hdev)
1591 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1592
1593 hci_dev_lock(hdev);
1594
1595 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1596 if (!cmd) {
1597 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001598 goto failed;
1599 }
1600
Brian Gixa68668b2011-08-11 15:49:36 -07001601 memset(&hci_cp, 0, sizeof(hci_cp));
1602 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1603 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1604 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001605 if (err < 0)
1606 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001607
1608failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001610 hci_dev_put(hdev);
1611
1612 return err;
1613}
1614
Johan Hedbergb312b1612011-03-16 14:29:37 +02001615static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1616 u16 len)
1617{
1618 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1619 struct hci_cp_write_local_name hci_cp;
1620 struct hci_dev *hdev;
1621 struct pending_cmd *cmd;
1622 int err;
1623
1624 BT_DBG("");
1625
1626 if (len != sizeof(*mgmt_cp))
1627 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1628
1629 hdev = hci_dev_get(index);
1630 if (!hdev)
1631 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001634
1635 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1636 if (!cmd) {
1637 err = -ENOMEM;
1638 goto failed;
1639 }
1640
1641 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1642 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1643 &hci_cp);
1644 if (err < 0)
1645 mgmt_pending_remove(cmd);
1646
1647failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001649 hci_dev_put(hdev);
1650
1651 return err;
1652}
1653
Brian Gixa68668b2011-08-11 15:49:36 -07001654static void discovery_rsp(struct pending_cmd *cmd, void *data)
1655{
1656 struct mgmt_mode ev;
1657
1658 BT_DBG("");
1659 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1660 ev.val = 1;
1661 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1662 } else {
1663 ev.val = 0;
1664 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1665 NULL, 0);
1666 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1667 struct disco_interleave *ilp = cmd->param;
1668
1669 del_timer_sync(&ilp->le_timer);
1670 del_timer_sync(&ilp->timer);
1671 }
1672 }
1673
1674 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1675
1676 list_del(&cmd->list);
1677
1678 mgmt_pending_free(cmd);
1679}
1680
1681void mgmt_inquiry_started(u16 index)
1682{
1683 BT_DBG("");
1684 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1685 discovery_rsp, NULL);
1686}
1687
1688void mgmt_inquiry_complete_evt(u16 index, u8 status)
1689{
1690 struct hci_dev *hdev;
1691 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1692 struct pending_cmd *cmd;
1693 int err = -1;
1694
1695 BT_DBG("");
1696
1697 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001698
1699 if (hdev)
1700 hci_dev_lock(hdev);
1701
Brian Gixa68668b2011-08-11 15:49:36 -07001702 if (!hdev || !lmp_le_capable(hdev)) {
1703 struct mgmt_mode cp = {0};
1704
1705 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1706 discovery_terminated, NULL);
1707
1708 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001709
Brian Gix64bd5302011-09-08 11:35:48 -07001710 if (hdev)
1711 goto done;
1712 else
1713 return;
1714 }
Brian Gixa68668b2011-08-11 15:49:36 -07001715
1716 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1717 if (cmd && cmd->param) {
1718 struct disco_interleave *ilp = cmd->param;
1719
1720 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1721 sizeof(le_cp), &le_cp);
1722 if (err >= 0) {
1723 mod_timer(&ilp->le_timer, jiffies +
1724 msecs_to_jiffies(ilp->int_phase * 1000));
1725 ilp->mode = SCAN_LE;
1726 } else
1727 ilp->mode = SCAN_IDLE;
1728 }
1729
1730 if (err < 0)
1731 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1732 discovery_terminated, NULL);
1733
Brian Gix64bd5302011-09-08 11:35:48 -07001734done:
Brian Gixa68668b2011-08-11 15:49:36 -07001735 hci_dev_unlock(hdev);
1736 hci_dev_put(hdev);
1737}
1738
1739static void disco_to(unsigned long data)
1740{
1741 struct disco_interleave *ilp = (void *)data;
1742 struct hci_dev *hdev;
1743 struct pending_cmd *cmd;
1744
1745 BT_DBG("hci%d", ilp->index);
1746
1747 del_timer_sync(&ilp->le_timer);
1748 hdev = hci_dev_get(ilp->index);
1749
1750 if (hdev) {
1751 hci_dev_lock(hdev);
1752
1753 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1754
1755 if (ilp->mode != SCAN_IDLE) {
1756 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1757
1758 if (ilp->mode == SCAN_LE)
1759 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1760 sizeof(le_cp), &le_cp);
1761 else
1762 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1763 0, NULL);
1764
1765 ilp->mode = SCAN_IDLE;
1766 }
1767
1768 if (cmd) {
1769 struct mgmt_mode cp = {0};
1770
1771 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1772 sizeof(cp), NULL);
1773 mgmt_pending_remove(cmd);
1774 }
1775
1776 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001777 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001778 }
1779}
1780
1781static void disco_le_to(unsigned long data)
1782{
1783 struct disco_interleave *ilp = (void *)data;
1784 struct hci_dev *hdev;
1785 struct pending_cmd *cmd;
1786 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1787
1788 BT_DBG("hci%d", ilp->index);
1789
1790 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001791
1792 if (hdev) {
1793 hci_dev_lock(hdev);
1794
1795 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1796
1797 if (ilp->mode == SCAN_LE)
1798 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1799 sizeof(le_cp), &le_cp);
1800
1801 /* re-start BR scan */
1802 if (cmd) {
1803 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1804 ilp->int_phase *= 2;
1805 ilp->int_count = 0;
1806 cp.num_rsp = (u8) ilp->int_phase;
1807 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1808 ilp->mode = SCAN_BR;
1809 } else
1810 ilp->mode = SCAN_IDLE;
1811
1812 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001813 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001814 }
1815}
1816
1817static int start_discovery(struct sock *sk, u16 index)
1818{
1819 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1820 struct hci_dev *hdev;
1821 struct pending_cmd *cmd;
1822 int err;
1823
1824 BT_DBG("");
1825
1826 hdev = hci_dev_get(index);
1827 if (!hdev)
1828 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1829
1830 hci_dev_lock(hdev);
1831
1832 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1833 if (!cmd) {
1834 err = -ENOMEM;
1835 goto failed;
1836 }
1837
1838 /* If LE Capable, we will alternate between BR/EDR and LE */
1839 if (lmp_le_capable(hdev)) {
1840 struct hci_cp_le_set_scan_parameters le_cp;
1841
1842 /* Shorten BR scan params */
1843 cp.num_rsp = 1;
1844 cp.length /= 2;
1845
1846 /* Setup LE scan params */
1847 memset(&le_cp, 0, sizeof(le_cp));
1848 le_cp.type = 0x01; /* Active scanning */
1849 /* The recommended value for scan interval and window is
1850 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1851 le_cp.interval = cpu_to_le16(0x0012);
1852 le_cp.window = cpu_to_le16(0x0012);
1853 le_cp.own_bdaddr_type = 0; /* Public address */
1854 le_cp.filter = 0; /* Accept all adv packets */
1855
1856 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1857 sizeof(le_cp), &le_cp);
1858 }
1859
1860 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1861
1862 if (err < 0)
1863 mgmt_pending_remove(cmd);
1864 else if (lmp_le_capable(hdev)) {
1865 struct disco_interleave il, *ilp;
1866
1867 il.int_phase = 1;
1868 il.int_count = 0;
1869 il.index = index;
1870 il.mode = SCAN_BR;
1871 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1872 sizeof(struct disco_interleave));
1873 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1874 if (cmd) {
1875 ilp = cmd->param;
1876 setup_timer(&ilp->le_timer, disco_le_to,
1877 (unsigned long) ilp);
1878 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1879 mod_timer(&ilp->timer,
1880 jiffies + msecs_to_jiffies(20000));
1881 }
1882 }
1883
1884failed:
1885 hci_dev_unlock(hdev);
1886 hci_dev_put(hdev);
1887
1888 return err;
1889}
1890
1891static int stop_discovery(struct sock *sk, u16 index)
1892{
1893 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1894 struct mgmt_mode mode_cp = {0};
1895 struct disco_interleave *ilp = NULL;
1896 struct hci_dev *hdev;
1897 struct pending_cmd *cmd = NULL;
1898 int err = -EPERM;
1899
1900 BT_DBG("");
1901
1902 hdev = hci_dev_get(index);
1903 if (!hdev)
1904 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1905
1906 hci_dev_lock(hdev);
1907
1908 if (lmp_le_capable(hdev)) {
1909 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1910 if (!cmd) {
1911 err = -ENOMEM;
1912 goto failed;
1913 }
1914
1915 ilp = cmd->param;
1916 }
1917
1918 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1919 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1920 sizeof(le_cp), &le_cp);
1921
1922 if (err < 0) {
1923 if (!ilp || (ilp->mode == SCAN_BR))
1924 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1925 0, NULL);
1926 }
1927
1928 if (ilp) {
1929 ilp->mode = SCAN_IDLE;
1930 del_timer_sync(&ilp->le_timer);
1931 del_timer_sync(&ilp->timer);
1932 }
1933
1934 if (err < 0 && cmd)
1935 mgmt_pending_remove(cmd);
1936
1937 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1938
1939failed:
1940 hci_dev_unlock(hdev);
1941 hci_dev_put(hdev);
1942
1943 if (err < 0)
1944 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1945 else
1946 return err;
1947}
1948
Szymon Jancc35938b2011-03-22 13:12:21 +01001949static int read_local_oob_data(struct sock *sk, u16 index)
1950{
1951 struct hci_dev *hdev;
1952 struct pending_cmd *cmd;
1953 int err;
1954
1955 BT_DBG("hci%u", index);
1956
1957 hdev = hci_dev_get(index);
1958 if (!hdev)
1959 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1960 ENODEV);
1961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001963
1964 if (!test_bit(HCI_UP, &hdev->flags)) {
1965 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1966 ENETDOWN);
1967 goto unlock;
1968 }
1969
1970 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1971 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1972 EOPNOTSUPP);
1973 goto unlock;
1974 }
1975
1976 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1977 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1978 goto unlock;
1979 }
1980
1981 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1982 if (!cmd) {
1983 err = -ENOMEM;
1984 goto unlock;
1985 }
1986
1987 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1988 if (err < 0)
1989 mgmt_pending_remove(cmd);
1990
1991unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001993 hci_dev_put(hdev);
1994
1995 return err;
1996}
1997
Szymon Janc2763eda2011-03-22 13:12:22 +01001998static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1999 u16 len)
2000{
2001 struct hci_dev *hdev;
2002 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2003 int err;
2004
2005 BT_DBG("hci%u ", index);
2006
2007 if (len != sizeof(*cp))
2008 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2009 EINVAL);
2010
2011 hdev = hci_dev_get(index);
2012 if (!hdev)
2013 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2014 ENODEV);
2015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002017
2018 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2019 cp->randomizer);
2020 if (err < 0)
2021 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2022 else
2023 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2024 0);
2025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002027 hci_dev_put(hdev);
2028
2029 return err;
2030}
2031
2032static int remove_remote_oob_data(struct sock *sk, u16 index,
2033 unsigned char *data, u16 len)
2034{
2035 struct hci_dev *hdev;
2036 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2037 int err;
2038
2039 BT_DBG("hci%u ", index);
2040
2041 if (len != sizeof(*cp))
2042 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2043 EINVAL);
2044
2045 hdev = hci_dev_get(index);
2046 if (!hdev)
2047 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2048 ENODEV);
2049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002050 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002051
2052 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2053 if (err < 0)
2054 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2055 -err);
2056 else
2057 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2058 NULL, 0);
2059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002061 hci_dev_put(hdev);
2062
2063 return err;
2064}
2065
Johan Hedberg03811012010-12-08 00:21:06 +02002066int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2067{
2068 unsigned char *buf;
2069 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002070 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002071 int err;
2072
2073 BT_DBG("got %zu bytes", msglen);
2074
2075 if (msglen < sizeof(*hdr))
2076 return -EINVAL;
2077
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002078 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002079 if (!buf)
2080 return -ENOMEM;
2081
2082 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2083 err = -EFAULT;
2084 goto done;
2085 }
2086
2087 hdr = (struct mgmt_hdr *) buf;
2088 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002089 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002090 len = get_unaligned_le16(&hdr->len);
2091
2092 if (len != msglen - sizeof(*hdr)) {
2093 err = -EINVAL;
2094 goto done;
2095 }
2096
Brian Gixa68668b2011-08-11 15:49:36 -07002097 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002098 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002099 case MGMT_OP_READ_VERSION:
2100 err = read_version(sk);
2101 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002102 case MGMT_OP_READ_INDEX_LIST:
2103 err = read_index_list(sk);
2104 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002105 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002106 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002107 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002108 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002109 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002110 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002111 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002113 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002114 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002116 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002117 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002118 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002119 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002120 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002122 break;
2123 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002124 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002126 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002127 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002128 break;
2129 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002130 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002131 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002132 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002133 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002134 break;
2135 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002136 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002137 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002138 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002139 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002140 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002141 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002142 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002144 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146 break;
2147 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002148 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002149 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002150 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002151 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002152 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002153 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002154 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002155 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002156 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002157 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002158 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002159 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2160 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002161 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002162 case MGMT_OP_SET_LOCAL_NAME:
2163 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2164 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002165 case MGMT_OP_START_DISCOVERY:
2166 err = start_discovery(sk, index);
2167 break;
2168 case MGMT_OP_STOP_DISCOVERY:
2169 err = stop_discovery(sk, index);
2170 break;
2171 case MGMT_OP_RESOLVE_NAME:
2172 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2173 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 case MGMT_OP_READ_LOCAL_OOB_DATA:
2175 err = read_local_oob_data(sk, index);
2176 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002177 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2178 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2179 break;
2180 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2181 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2182 len);
2183 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184
Johan Hedberg03811012010-12-08 00:21:06 +02002185 default:
2186 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002187 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002188 break;
2189 }
2190
Johan Hedberge41d8b42010-12-13 21:07:03 +02002191 if (err < 0)
2192 goto done;
2193
Johan Hedberg03811012010-12-08 00:21:06 +02002194 err = msglen;
2195
2196done:
2197 kfree(buf);
2198 return err;
2199}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002200
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002201int mgmt_index_added(u16 index)
2202{
Brian Gixa68668b2011-08-11 15:49:36 -07002203 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002204 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002205}
2206
2207int mgmt_index_removed(u16 index)
2208{
Brian Gixa68668b2011-08-11 15:49:36 -07002209 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002210 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002211}
2212
Johan Hedberg73f22f62010-12-29 16:00:25 +02002213struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002214 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002215 struct sock *sk;
2216};
2217
Johan Hedberg72a734e2010-12-30 00:38:22 +02002218static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002219{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002220 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002221 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002222
Johan Hedberg72a734e2010-12-30 00:38:22 +02002223 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002224 return;
2225
Johan Hedberg053f0212011-01-26 13:07:10 +02002226 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002227
2228 list_del(&cmd->list);
2229
2230 if (match->sk == NULL) {
2231 match->sk = cmd->sk;
2232 sock_hold(match->sk);
2233 }
2234
2235 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002236}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002237
2238int mgmt_powered(u16 index, u8 powered)
2239{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002240 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002241 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002242 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002243
Brian Gixa68668b2011-08-11 15:49:36 -07002244 BT_DBG("hci%u %d", index, powered);
2245
Johan Hedberg72a734e2010-12-30 00:38:22 +02002246 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002247
Johan Hedberg72a734e2010-12-30 00:38:22 +02002248 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002249
Szymon Janc4e51eae2011-02-25 19:05:48 +01002250 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002251
2252 if (match.sk)
2253 sock_put(match.sk);
2254
2255 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002256}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002257
Johan Hedberg73f22f62010-12-29 16:00:25 +02002258int mgmt_discoverable(u16 index, u8 discoverable)
2259{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002260 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002261 struct cmd_lookup match = { discoverable, NULL };
2262 int ret;
2263
Szymon Jancb8534e02011-03-01 16:55:34 +01002264 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002265
Johan Hedberg72a734e2010-12-30 00:38:22 +02002266 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002267
Szymon Janc4e51eae2011-02-25 19:05:48 +01002268 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2269 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002270
2271 if (match.sk)
2272 sock_put(match.sk);
2273
2274 return ret;
2275}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002276
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002277int mgmt_connectable(u16 index, u8 connectable)
2278{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002279 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002280 struct cmd_lookup match = { connectable, NULL };
2281 int ret;
2282
Johan Hedberg72a734e2010-12-30 00:38:22 +02002283 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002284
Johan Hedberg72a734e2010-12-30 00:38:22 +02002285 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002286
Szymon Janc4e51eae2011-02-25 19:05:48 +01002287 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002288
2289 if (match.sk)
2290 sock_put(match.sk);
2291
2292 return ret;
2293}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002294
Brian Gixa68668b2011-08-11 15:49:36 -07002295int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002296{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002297 struct mgmt_ev_new_key *ev;
2298 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002299
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002300 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2301 ev = kzalloc(total, GFP_ATOMIC);
2302 if (!ev)
2303 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002304
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002305 bacpy(&ev->key.bdaddr, &key->bdaddr);
2306 ev->key.type = key->type;
2307 memcpy(ev->key.val, key->val, 16);
2308 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002309 ev->key.auth = key->auth;
2310 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002311 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002312
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002313 memcpy(ev->key.data, key->data, key->dlen);
2314
2315 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2316
2317 kfree(ev);
2318
2319 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002320}
Johan Hedbergf7520542011-01-20 12:34:39 +02002321
Brian Gix2e2f50d2011-09-13 12:36:04 -07002322int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002323{
2324 struct mgmt_ev_connected ev;
2325
Johan Hedbergf7520542011-01-20 12:34:39 +02002326 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002327 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002328
Szymon Janc4e51eae2011-02-25 19:05:48 +01002329 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002330}
2331
Johan Hedberg8962ee72011-01-20 12:40:27 +02002332static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2333{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002334 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002336 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002337
Johan Hedberga38528f2011-01-22 06:46:43 +02002338 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002339
Szymon Janc4e51eae2011-02-25 19:05:48 +01002340 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002341
2342 *sk = cmd->sk;
2343 sock_hold(*sk);
2344
Johan Hedberga664b5b2011-02-19 12:06:02 -03002345 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002346}
2347
Johan Hedbergf7520542011-01-20 12:34:39 +02002348int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2349{
2350 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002351 struct sock *sk = NULL;
2352 int err;
2353
2354 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002355
Johan Hedbergf7520542011-01-20 12:34:39 +02002356 bacpy(&ev.bdaddr, bdaddr);
2357
Szymon Janc4e51eae2011-02-25 19:05:48 +01002358 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002359
2360 if (sk)
2361 sock_put(sk);
2362
2363 return err;
2364}
2365
2366int mgmt_disconnect_failed(u16 index)
2367{
2368 struct pending_cmd *cmd;
2369 int err;
2370
2371 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2372 if (!cmd)
2373 return -ENOENT;
2374
Szymon Janc4e51eae2011-02-25 19:05:48 +01002375 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002376
Johan Hedberga664b5b2011-02-19 12:06:02 -03002377 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002378
2379 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002380}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002381
2382int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2383{
2384 struct mgmt_ev_connect_failed ev;
2385
Johan Hedberg17d5c042011-01-22 06:09:08 +02002386 bacpy(&ev.bdaddr, bdaddr);
2387 ev.status = status;
2388
Szymon Janc4e51eae2011-02-25 19:05:48 +01002389 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002390}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002393{
2394 struct mgmt_ev_pin_code_request ev;
2395
Brian Gixa68668b2011-08-11 15:49:36 -07002396 BT_DBG("hci%u", index);
2397
Johan Hedberg980e1a52011-01-22 06:10:07 +02002398 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002399 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002400
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2402 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002403}
2404
2405int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2406{
2407 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002408 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002409 int err;
2410
2411 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2412 if (!cmd)
2413 return -ENOENT;
2414
Johan Hedbergac56fb12011-02-19 12:05:59 -03002415 bacpy(&rp.bdaddr, bdaddr);
2416 rp.status = status;
2417
Szymon Janc4e51eae2011-02-25 19:05:48 +01002418 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2419 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002420
Johan Hedberga664b5b2011-02-19 12:06:02 -03002421 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002422
2423 return err;
2424}
2425
2426int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2427{
2428 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002429 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002430 int err;
2431
2432 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2433 if (!cmd)
2434 return -ENOENT;
2435
Johan Hedbergac56fb12011-02-19 12:05:59 -03002436 bacpy(&rp.bdaddr, bdaddr);
2437 rp.status = status;
2438
Szymon Janc4e51eae2011-02-25 19:05:48 +01002439 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2440 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002441
Johan Hedberga664b5b2011-02-19 12:06:02 -03002442 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002443
2444 return err;
2445}
Johan Hedberga5c29682011-02-19 12:05:57 -03002446
Brian Gixa68668b2011-08-11 15:49:36 -07002447int mgmt_user_confirm_request(u16 index, u8 event,
2448 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002449{
2450 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002451 struct hci_conn *conn = NULL;
2452 struct hci_dev *hdev;
2453 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2454
2455 BT_DBG("hci%u", index);
2456
2457 hdev = hci_dev_get(index);
2458
Brian Gix64bd5302011-09-08 11:35:48 -07002459 if (!hdev)
2460 return -ENODEV;
2461
Brian Gix64bd5302011-09-08 11:35:48 -07002462 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002463
2464 ev.auto_confirm = 0;
2465
2466 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2467 goto no_auto_confirm;
2468
2469 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2470 rem_cap = conn->remote_cap;
2471 loc_mitm = conn->auth_type & 0x01;
2472 rem_mitm = conn->remote_auth & 0x01;
2473
2474 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2475 goto no_auto_confirm;
2476
2477
2478 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2479 ev.auto_confirm = 1;
2480
2481no_auto_confirm:
2482 bacpy(&ev.bdaddr, bdaddr);
2483 ev.event = event;
2484 put_unaligned_le32(value, &ev.value);
2485
Brian Gix64bd5302011-09-08 11:35:48 -07002486 hci_dev_put(hdev);
2487
Brian Gixa68668b2011-08-11 15:49:36 -07002488 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2489 NULL);
2490}
2491
2492int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2493{
2494 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002495
2496 BT_DBG("hci%u", index);
2497
Johan Hedberga5c29682011-02-19 12:05:57 -03002498 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002499
Brian Gixa68668b2011-08-11 15:49:36 -07002500 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002501 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002502}
2503
2504static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2505 u8 opcode)
2506{
2507 struct pending_cmd *cmd;
2508 struct mgmt_rp_user_confirm_reply rp;
2509 int err;
2510
2511 cmd = mgmt_pending_find(opcode, index);
2512 if (!cmd)
2513 return -ENOENT;
2514
Johan Hedberga5c29682011-02-19 12:05:57 -03002515 bacpy(&rp.bdaddr, bdaddr);
2516 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002517 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002518
Johan Hedberga664b5b2011-02-19 12:06:02 -03002519 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002520
2521 return err;
2522}
2523
2524int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2525{
2526 return confirm_reply_complete(index, bdaddr, status,
2527 MGMT_OP_USER_CONFIRM_REPLY);
2528}
2529
Szymon Jancb8534e02011-03-01 16:55:34 +01002530int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002531{
2532 return confirm_reply_complete(index, bdaddr, status,
2533 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2534}
Johan Hedberg2a611692011-02-19 12:06:00 -03002535
2536int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2537{
2538 struct mgmt_ev_auth_failed ev;
2539
Johan Hedberg2a611692011-02-19 12:06:00 -03002540 bacpy(&ev.bdaddr, bdaddr);
2541 ev.status = status;
2542
Szymon Janc4e51eae2011-02-25 19:05:48 +01002543 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002544}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002545
2546int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2547{
2548 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002549 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002550 struct mgmt_cp_set_local_name ev;
2551 int err;
2552
2553 memset(&ev, 0, sizeof(ev));
2554 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2555
2556 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2557 if (!cmd)
2558 goto send_event;
2559
2560 if (status) {
2561 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2562 goto failed;
2563 }
2564
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002565 hdev = hci_dev_get(index);
2566 if (hdev) {
2567 hci_dev_lock_bh(hdev);
2568 update_eir(hdev);
2569 hci_dev_unlock_bh(hdev);
2570 hci_dev_put(hdev);
2571 }
2572
Johan Hedbergb312b1612011-03-16 14:29:37 +02002573 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2574 sizeof(ev));
2575 if (err < 0)
2576 goto failed;
2577
2578send_event:
2579 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2580 cmd ? cmd->sk : NULL);
2581
2582failed:
2583 if (cmd)
2584 mgmt_pending_remove(cmd);
2585 return err;
2586}
Szymon Jancc35938b2011-03-22 13:12:21 +01002587
2588int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2589 u8 status)
2590{
2591 struct pending_cmd *cmd;
2592 int err;
2593
2594 BT_DBG("hci%u status %u", index, status);
2595
2596 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2597 if (!cmd)
2598 return -ENOENT;
2599
2600 if (status) {
2601 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2602 EIO);
2603 } else {
2604 struct mgmt_rp_read_local_oob_data rp;
2605
2606 memcpy(rp.hash, hash, sizeof(rp.hash));
2607 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2608
2609 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2610 &rp, sizeof(rp));
2611 }
2612
2613 mgmt_pending_remove(cmd);
2614
2615 return err;
2616}
Johan Hedberge17acd42011-03-30 23:57:16 +03002617
Brian Gixa68668b2011-08-11 15:49:36 -07002618int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2619 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002620{
2621 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002622 struct pending_cmd *cmd;
2623 int err;
2624
2625 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002626
2627 memset(&ev, 0, sizeof(ev));
2628
2629 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002630 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002631 ev.type = type;
2632 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002633
Brian Gixa68668b2011-08-11 15:49:36 -07002634 if (dev_class)
2635 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002636
Brian Gixa68668b2011-08-11 15:49:36 -07002637 if (eir && eir_len)
2638 memcpy(ev.eir, eir, eir_len);
2639
2640 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2641
2642 if (err < 0)
2643 return err;
2644
2645 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2646 if (cmd) {
2647 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002648 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002649
2650 ilp->int_count++;
2651 if (hdev && ilp->int_count >= ilp->int_phase) {
2652 /* Inquiry scan for General Discovery LAP */
2653 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2654 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002655
Brian Gixa68668b2011-08-11 15:49:36 -07002656 ilp->int_phase *= 2;
2657 ilp->int_count = 0;
2658 if (ilp->mode == SCAN_LE) {
2659 /* cancel LE scan */
2660 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2661 sizeof(le_cp), &le_cp);
2662 /* start BR scan */
2663 cp.num_rsp = (u8) ilp->int_phase;
2664 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2665 sizeof(cp), &cp);
2666 ilp->mode = SCAN_BR;
2667 del_timer_sync(&ilp->le_timer);
2668 }
2669 }
Brian Gix64bd5302011-09-08 11:35:48 -07002670
2671 if (hdev)
2672 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002673 }
2674
2675 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002676}
Johan Hedberga88a9652011-03-30 13:18:12 +03002677
Brian Gixa68668b2011-08-11 15:49:36 -07002678
2679int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002680{
2681 struct mgmt_ev_remote_name ev;
2682
2683 memset(&ev, 0, sizeof(ev));
2684
2685 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002686 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002687 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2688
2689 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2690}