blob: dce84913c6846faf5f017949fcc14895155290e6 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
Brian Gix568dde92012-01-11 16:18:04 -08004 Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
Johan Hedberg03811012010-12-08 00:21:06 +02005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
24/* Bluetooth HCI Management interface */
25
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/interrupt.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040028#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020029#include <asm/unaligned.h>
30
31#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010039
Brian Gix568dde92012-01-11 16:18:04 -080040#define SCAN_IDLE 0x00
41#define SCAN_LE 0x01
42#define SCAN_BR 0x02
Johan Hedberg4b34ee782012-02-21 14:13:02 +020043
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044struct pending_cmd {
45 struct list_head list;
46 __u16 opcode;
47 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010048 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030050 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020051};
52
Mat Martineau8cd0df02011-08-23 16:23:36 -070053struct mgmt_pending_free_work {
54 struct work_struct work;
55 struct sock *sk;
Johan Hedbergca69b792011-11-11 18:10:00 +020056};
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058LIST_HEAD(cmd_list);
Johan Hedbergca69b792011-11-11 18:10:00 +020059
Szymon Janc4e51eae2011-02-25 19:05:48 +010060static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020061{
62 struct sk_buff *skb;
63 struct mgmt_hdr *hdr;
64 struct mgmt_ev_cmd_status *ev;
65
Szymon Janc34eb5252011-02-28 14:10:08 +010066 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020067
68 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
69 if (!skb)
70 return -ENOMEM;
71
72 hdr = (void *) skb_put(skb, sizeof(*hdr));
73
74 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010075 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076 hdr->len = cpu_to_le16(sizeof(*ev));
77
78 ev = (void *) skb_put(skb, sizeof(*ev));
79 ev->status = status;
80 put_unaligned_le16(cmd, &ev->opcode);
81
82 if (sock_queue_rcv_skb(sk, skb) < 0)
83 kfree_skb(skb);
84
85 return 0;
86}
87
Szymon Janc4e51eae2011-02-25 19:05:48 +010088static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
89 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020090{
91 struct sk_buff *skb;
92 struct mgmt_hdr *hdr;
93 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020094
95 BT_DBG("sock %p", sk);
96
Johan Hedberga38528f2011-01-22 06:46:43 +020097 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020098 if (!skb)
99 return -ENOMEM;
100
101 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200102
Johan Hedberg02d98122010-12-13 21:07:04 +0200103 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100104 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106
Johan Hedberga38528f2011-01-22 06:46:43 +0200107 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
108 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100109
110 if (rp)
111 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200112
113 if (sock_queue_rcv_skb(sk, skb) < 0)
114 kfree_skb(skb);
115
116 return 0;
117}
118
Johan Hedberga38528f2011-01-22 06:46:43 +0200119static int read_version(struct sock *sk)
120{
121 struct mgmt_rp_read_version rp;
122
123 BT_DBG("sock %p", sk);
124
125 rp.version = MGMT_VERSION;
126 put_unaligned_le16(MGMT_REVISION, &rp.revision);
127
Szymon Janc4e51eae2011-02-25 19:05:48 +0100128 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
129 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200130}
131
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132static int read_index_list(struct sock *sk)
133{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134 struct mgmt_rp_read_index_list *rp;
135 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200138 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139
140 BT_DBG("sock %p", sk);
141
142 read_lock(&hci_dev_list_lock);
143
144 count = 0;
145 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
147 if (d->dev_type != HCI_BREDR)
148 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Peter Krystad1fc44072011-08-30 15:38:12 -0700167 if (d->dev_type != HCI_BREDR)
168 continue;
169
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200170 set_bit(HCI_MGMT, &d->flags);
171
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172 if (test_bit(HCI_SETUP, &d->flags))
173 continue;
174
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200175 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700176 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200177 BT_DBG("Added hci%u", d->id);
178 }
179
180 read_unlock(&hci_dev_list_lock);
181
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
183 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200184
Johan Hedberga38528f2011-01-22 06:46:43 +0200185 kfree(rp);
186
187 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200188}
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200191{
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200201 hci_del_off_timer(hdev);
202
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800203 hci_dev_lock_bh(hdev);
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100204
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200205 set_bit(HCI_MGMT, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200207 memset(&rp, 0, sizeof(rp));
208
Johan Hedberga38528f2011-01-22 06:46:43 +0200209 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Johan Hedberga38528f2011-01-22 06:46:43 +0200211 rp.powered = test_bit(HCI_UP, &hdev->flags);
212 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
213 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
214 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200221 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222
Johan Hedberga38528f2011-01-22 06:46:43 +0200223 bacpy(&rp.bdaddr, &hdev->bdaddr);
224 memcpy(rp.features, hdev->features, 8);
225 memcpy(rp.dev_class, hdev->dev_class, 3);
226 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
227 rp.hci_ver = hdev->hci_ver;
228 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200230 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
231
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800232 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200233 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200234
Szymon Janc4e51eae2011-02-25 19:05:48 +0100235 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200236}
Johan Hedberg03811012010-12-08 00:21:06 +0200237
Mat Martineau8cd0df02011-08-23 16:23:36 -0700238static void mgmt_pending_free_worker(struct work_struct *work)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200239{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700240 struct mgmt_pending_free_work *free_work =
241 container_of(work, struct mgmt_pending_free_work, work);
Johan Hedberg03811012010-12-08 00:21:06 +0200242
Mat Martineau8cd0df02011-08-23 16:23:36 -0700243 BT_DBG("sk %p", free_work->sk);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100244
Mat Martineau8cd0df02011-08-23 16:23:36 -0700245 sock_put(free_work->sk);
246 kfree(free_work);
Johan Hedbergc542a062011-01-26 13:11:03 +0200247}
248
Johan Hedberg03811012010-12-08 00:21:06 +0200249static void mgmt_pending_free(struct pending_cmd *cmd)
250{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700251 struct mgmt_pending_free_work *free_work;
252 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700253
Mat Martineau8cd0df02011-08-23 16:23:36 -0700254 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
255
Johan Hedberg03811012010-12-08 00:21:06 +0200256 kfree(cmd->param);
257 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700258
259 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
260 if (free_work) {
261 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
262 free_work->sk = sk;
263
264 if (!schedule_work(&free_work->work))
265 kfree(free_work);
266 }
Johan Hedberg03811012010-12-08 00:21:06 +0200267}
268
269static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
270 u16 index, void *data, u16 len)
271{
272 struct pending_cmd *cmd;
273
Brian Gixa68668b2011-08-11 15:49:36 -0700274 BT_DBG("%d", opcode);
275
Johan Hedberg03811012010-12-08 00:21:06 +0200276 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
277 if (!cmd)
278 return NULL;
279
280 cmd->opcode = opcode;
281 cmd->index = index;
282
283 cmd->param = kmalloc(len, GFP_ATOMIC);
284 if (!cmd->param) {
285 kfree(cmd);
286 return NULL;
287 }
288
289 if (data)
290 memcpy(cmd->param, data, len);
291
292 cmd->sk = sk;
293 sock_hold(sk);
294
295 list_add(&cmd->list, &cmd_list);
296
297 return cmd;
298}
299
300static void mgmt_pending_foreach(u16 opcode, int index,
301 void (*cb)(struct pending_cmd *cmd, void *data),
302 void *data)
Johan Hedberge41d8b42010-12-13 21:07:03 +0200303{
304 struct list_head *p, *n;
Johan Hedberg03811012010-12-08 00:21:06 +0200305
Brian Gixa68668b2011-08-11 15:49:36 -0700306 BT_DBG(" %d", opcode);
307
Johan Hedberg03811012010-12-08 00:21:06 +0200308 list_for_each_safe(p, n, &cmd_list) {
309 struct pending_cmd *cmd;
310
311 cmd = list_entry(p, struct pending_cmd, list);
312
Johan Hedberg931bc4e2011-11-03 14:40:33 +0200313 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedberg03811012010-12-08 00:21:06 +0200314 continue;
315
316 if (index >= 0 && cmd->index != index)
317 continue;
318
319 cb(cmd, data);
320 }
321}
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200322
323static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
324{
325 struct list_head *p;
326
Brian Gixa68668b2011-08-11 15:49:36 -0700327 BT_DBG(" %d", opcode);
328
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 list_for_each(p, &cmd_list) {
330 struct pending_cmd *cmd;
331
332 cmd = list_entry(p, struct pending_cmd, list);
333
334 if (cmd->opcode != opcode)
335 continue;
336
337 if (index >= 0 && cmd->index != index)
338 continue;
339
340 return cmd;
341 }
342
343 return NULL;
344}
345
346static void mgmt_pending_remove(struct pending_cmd *cmd)
347{
Brian Gixa68668b2011-08-11 15:49:36 -0700348 BT_DBG(" %d", cmd->opcode);
349
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350 list_del(&cmd->list);
351 mgmt_pending_free(cmd);
352}
353
354static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
355{
356 struct mgmt_mode *cp;
357 struct hci_dev *hdev;
358 struct pending_cmd *cmd;
359 int err, up;
360
361 cp = (void *) data;
362
363 BT_DBG("request for hci%u", index);
364
365 if (len != sizeof(*cp))
366 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
367
368 hdev = hci_dev_get(index);
369 if (!hdev)
370 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
371
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800372 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200373
374 up = test_bit(HCI_UP, &hdev->flags);
375 if ((cp->val && up) || (!cp->val && !up)) {
376 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
377 goto failed;
378 }
379
380 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
381 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
382 goto failed;
383 }
384
385 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
386 if (!cmd) {
387 err = -ENOMEM;
388 goto failed;
389 }
390
391 if (cp->val)
392 queue_work(hdev->workqueue, &hdev->power_on);
393 else
394 queue_work(hdev->workqueue, &hdev->power_off);
395
396 err = 0;
397
398failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800399 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200400 hci_dev_put(hdev);
401 return err;
402}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
Brian Gix8a7f1642011-10-17 17:39:46 -0700404static u8 get_service_classes(struct hci_dev *hdev)
405{
406 struct list_head *p;
407 u8 val = 0;
408
409 list_for_each(p, &hdev->uuids) {
410 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
411
412 val |= uuid->svc_hint;
413 }
414
415 return val;
416}
417
418static int update_class(struct hci_dev *hdev)
419{
420 u8 cod[3];
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530421 int err = 0;
Brian Gix8a7f1642011-10-17 17:39:46 -0700422
423 BT_DBG("%s", hdev->name);
424
425 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
426 return 0;
427
428 cod[0] = hdev->minor_class;
429 cod[1] = hdev->major_class;
430 cod[2] = get_service_classes(hdev);
431
432 if (memcmp(cod, hdev->dev_class, 3) == 0)
433 return 0;
434
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530435 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
436
437 if (err == 0)
438 memcpy(hdev->dev_class, cod, 3);
439
440 return err;
Brian Gix8a7f1642011-10-17 17:39:46 -0700441}
442
443static int set_limited_discoverable(struct sock *sk, u16 index,
444 unsigned char *data, u16 len)
445{
446 struct mgmt_mode *cp;
447 struct hci_dev *hdev;
448 struct pending_cmd *cmd;
449 struct hci_cp_write_current_iac_lap dcp;
450 int update_cod;
451 int err = 0;
452 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
453 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
454
455 cp = (void *) data;
456
457 BT_DBG("hci%u discoverable: %d", index, cp->val);
458
459 if (!cp || len != sizeof(*cp))
460 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
461 EINVAL);
462
463 hdev = hci_dev_get(index);
464 if (!hdev)
465 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
466 ENODEV);
467
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800468 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700469
470 if (!test_bit(HCI_UP, &hdev->flags)) {
471 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
472 ENETDOWN);
473 goto failed;
474 }
475
476 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
477 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
478 EBUSY);
479 goto failed;
480 }
481
482 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
483 test_bit(HCI_PSCAN, &hdev->flags)) {
484 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
485 EALREADY);
486 goto failed;
487 }
488
489 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
490 len);
491 if (!cmd) {
492 err = -ENOMEM;
493 goto failed;
494 }
495
496 memset(&dcp, 0, sizeof(dcp));
497 dcp.num_current_iac = cp->val ? 2 : 1;
498 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
499 update_cod = 1;
500
501 if (cp->val) {
502 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
503 update_cod = 0;
504 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
505 } else {
506 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
507 update_cod = 0;
508 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
509 }
510
511 if (update_cod)
512 err = update_class(hdev);
513
514 if (err >= 0)
515 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
516 sizeof(dcp), &dcp);
517
518 if (err < 0)
519 mgmt_pending_remove(cmd);
520
521failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800522 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700523 hci_dev_put(hdev);
524
525 return err;
526}
527
Johan Hedberg73f22f62010-12-29 16:00:25 +0200528static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
529 u16 len)
530{
531 struct mgmt_mode *cp;
532 struct hci_dev *hdev;
533 struct pending_cmd *cmd;
534 u8 scan;
535 int err;
536
537 cp = (void *) data;
538
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200539 BT_DBG("request for hci%u", index);
540
Johan Hedberg72a734e2010-12-30 00:38:22 +0200541 if (len != sizeof(*cp))
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200542 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
543
544 hdev = hci_dev_get(index);
545 if (!hdev)
546 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
547
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800548 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200549
550 if (!test_bit(HCI_UP, &hdev->flags)) {
551 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
552 goto failed;
553 }
554
555 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
556 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
557 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200558 goto failed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200559 }
560
561 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
562 test_bit(HCI_PSCAN, &hdev->flags)) {
563 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
564 goto failed;
565 }
566
567 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
568 if (!cmd) {
569 err = -ENOMEM;
570 goto failed;
571 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200572
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200573 scan = SCAN_PAGE;
574
575 if (cp->val)
576 scan |= SCAN_INQUIRY;
577
578 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
579 if (err < 0)
580 mgmt_pending_remove(cmd);
581
582failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800583 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200584 hci_dev_put(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200585
586 return err;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200587}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200588
589static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
590 u16 len)
591{
592 struct mgmt_mode *cp;
593 struct hci_dev *hdev;
594 struct pending_cmd *cmd;
595 u8 scan;
596 int err;
597
598 cp = (void *) data;
599
600 BT_DBG("request for hci%u", index);
601
602 if (len != sizeof(*cp))
603 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
604
605 hdev = hci_dev_get(index);
606 if (!hdev)
607 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
608
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800609 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200610
Johan Hedberg73f22f62010-12-29 16:00:25 +0200611 if (!test_bit(HCI_UP, &hdev->flags)) {
612 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
613 goto failed;
614 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200615
Johan Hedberg73f22f62010-12-29 16:00:25 +0200616 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
617 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
618 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
619 goto failed;
620 }
621
622 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
623 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
624 goto failed;
625 }
626
Johan Hedberg72a734e2010-12-30 00:38:22 +0200627 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200628 if (!cmd) {
629 err = -ENOMEM;
630 goto failed;
631 }
632
633 if (cp->val)
634 scan = SCAN_PAGE;
635 else
636 scan = 0;
637
638 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
639 if (err < 0)
640 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200641
642failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800643 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200644 hci_dev_put(hdev);
645
646 return err;
647}
648
649static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
650 struct sock *skip_sk)
651{
652 struct sk_buff *skb;
653 struct mgmt_hdr *hdr;
654
Brian Gixa68668b2011-08-11 15:49:36 -0700655 BT_DBG("hci%d %d", index, event);
656
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200657 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
658 if (!skb)
659 return -ENOMEM;
660
661 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
662
663 hdr = (void *) skb_put(skb, sizeof(*hdr));
664 hdr->opcode = cpu_to_le16(event);
665 hdr->index = cpu_to_le16(index);
666 hdr->len = cpu_to_le16(data_len);
667
668 if (data)
669 memcpy(skb_put(skb, data_len), data, data_len);
670
671 hci_send_to_sock(NULL, skb, skip_sk);
672 kfree_skb(skb);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200673
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200674 return 0;
675}
676
677static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
678{
679 struct mgmt_mode rp;
680
681 rp.val = val;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200682
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200683 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
684}
685
686static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
687 u16 len)
688{
689 struct mgmt_mode *cp, ev;
690 struct hci_dev *hdev;
691 int err;
692
693 cp = (void *) data;
694
695 BT_DBG("request for hci%u", index);
696
697 if (len != sizeof(*cp))
Johan Hedberg053f0212011-01-26 13:07:10 +0200698 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
699
700 hdev = hci_dev_get(index);
701 if (!hdev)
702 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
703
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800704 hci_dev_lock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200705
706 if (cp->val)
707 set_bit(HCI_PAIRABLE, &hdev->flags);
708 else
709 clear_bit(HCI_PAIRABLE, &hdev->flags);
710
711 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
712 if (err < 0)
713 goto failed;
714
715 ev.val = cp->val;
716
717 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
718
719failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800720 hci_dev_unlock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200721 hci_dev_put(hdev);
722
723 return err;
724}
725
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300726#define EIR_FLAGS 0x01 /* flags */
727#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
728#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
729#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
730#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
731#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
732#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
733#define EIR_NAME_SHORT 0x08 /* shortened local name */
734#define EIR_NAME_COMPLETE 0x09 /* complete local name */
735#define EIR_TX_POWER 0x0A /* transmit power level */
736#define EIR_DEVICE_ID 0x10 /* device ID */
737
738#define PNP_INFO_SVCLASS_ID 0x1200
739
740static u8 bluetooth_base_uuid[] = {
741 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
742 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743};
744
745static u16 get_uuid16(u8 *uuid128)
746{
747 u32 val;
748 int i;
749
750 for (i = 0; i < 12; i++) {
751 if (bluetooth_base_uuid[i] != uuid128[i])
752 return 0;
753 }
754
755 memcpy(&val, &uuid128[12], 4);
756
757 val = le32_to_cpu(val);
758 if (val > 0xffff)
759 return 0;
760
761 return (u16) val;
762}
763
764static void create_eir(struct hci_dev *hdev, u8 *data)
765{
766 u8 *ptr = data;
767 u16 eir_len = 0;
768 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
769 int i, truncated = 0;
770 struct list_head *p;
771 size_t name_len;
772
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530773 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300774
775 if (name_len > 0) {
776 /* EIR Data type */
777 if (name_len > 48) {
778 name_len = 48;
779 ptr[1] = EIR_NAME_SHORT;
780 } else
781 ptr[1] = EIR_NAME_COMPLETE;
782
783 /* EIR Data length */
784 ptr[0] = name_len + 1;
785
786 memcpy(ptr + 2, hdev->dev_name, name_len);
787
788 eir_len += (name_len + 2);
789 ptr += (name_len + 2);
790 }
791
792 memset(uuid16_list, 0, sizeof(uuid16_list));
793
794 /* Group all UUID16 types */
795 list_for_each(p, &hdev->uuids) {
796 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
797 u16 uuid16;
798
799 uuid16 = get_uuid16(uuid->uuid);
800 if (uuid16 == 0)
801 return;
802
803 if (uuid16 < 0x1100)
804 continue;
805
806 if (uuid16 == PNP_INFO_SVCLASS_ID)
807 continue;
808
809 /* Stop if not enough space to put next UUID */
810 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
811 truncated = 1;
812 break;
813 }
814
815 /* Check for duplicates */
816 for (i = 0; uuid16_list[i] != 0; i++)
817 if (uuid16_list[i] == uuid16)
818 break;
819
820 if (uuid16_list[i] == 0) {
821 uuid16_list[i] = uuid16;
822 eir_len += sizeof(u16);
823 }
824 }
825
826 if (uuid16_list[0] != 0) {
827 u8 *length = ptr;
828
829 /* EIR Data type */
830 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
831
832 ptr += 2;
833 eir_len += 2;
834
835 for (i = 0; uuid16_list[i] != 0; i++) {
836 *ptr++ = (uuid16_list[i] & 0x00ff);
837 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
838 }
839
840 /* EIR Data length */
841 *length = (i * sizeof(u16)) + 1;
842 }
843}
844
845static int update_eir(struct hci_dev *hdev)
846{
847 struct hci_cp_write_eir cp;
848
849 if (!(hdev->features[6] & LMP_EXT_INQ))
850 return 0;
851
852 if (hdev->ssp_mode == 0)
853 return 0;
854
855 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
856 return 0;
857
858 memset(&cp, 0, sizeof(cp));
859
860 create_eir(hdev, cp.data);
861
862 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
863 return 0;
864
865 memcpy(hdev->eir, cp.data, sizeof(cp.data));
866
867 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
868}
869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200871{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200872 struct mgmt_cp_add_uuid *cp;
873 struct hci_dev *hdev;
874 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200875 int err;
876
877 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200879 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200880
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881 if (len != sizeof(*cp))
882 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
883
884 hdev = hci_dev_get(index);
885 if (!hdev)
886 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
887
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800888 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200889
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
891 if (!uuid) {
892 err = -ENOMEM;
893 goto failed;
894 }
895
896 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200898
899 list_add(&uuid->list, &hdev->uuids);
900
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530901 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530903 err = update_class(hdev);
904 if (err < 0)
905 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300906
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530907 err = update_eir(hdev);
908 if (err < 0)
909 goto failed;
910 } else
911 err = 0;
Johan Hedberg90e70452012-02-23 23:09:40 +0200912
Szymon Janc4e51eae2011-02-25 19:05:48 +0100913 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200914
915failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800916 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200917 hci_dev_put(hdev);
918
919 return err;
920}
921
Szymon Janc4e51eae2011-02-25 19:05:48 +0100922static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg24b78d02012-02-23 23:24:30 +0200923{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100925 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200926 struct hci_dev *hdev;
927 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 +0200928 int err, found;
929
930 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200931
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200932 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200933
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934 if (len != sizeof(*cp))
935 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
936
937 hdev = hci_dev_get(index);
938 if (!hdev)
939 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
940
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800941 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200942
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200943 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
944 err = hci_uuids_clear(hdev);
945 goto unlock;
946 }
947
948 found = 0;
949
950 list_for_each_safe(p, n, &hdev->uuids) {
951 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
952
953 if (memcmp(match->uuid, cp->uuid, 16) != 0)
954 continue;
955
956 list_del(&match->list);
957 found++;
958 }
959
960 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200962 goto unlock;
963 }
964
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530965 if (test_bit(HCI_UP, &hdev->flags)) {
966 err = update_class(hdev);
967 if (err < 0)
968 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200969
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530970 err = update_eir(hdev);
971 if (err < 0)
972 goto unlock;
973 } else
974 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300975
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200977
978unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800979 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200980 hci_dev_put(hdev);
981
982 return err;
983}
984
Szymon Janc4e51eae2011-02-25 19:05:48 +0100985static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
986 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200987{
988 struct hci_dev *hdev;
989 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200990 int err;
991
992 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200993
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200995
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996 if (len != sizeof(*cp))
997 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200998
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200999 hdev = hci_dev_get(index);
1000 if (!hdev)
1001 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
1002
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001003 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004
Brian Gix8a7f1642011-10-17 17:39:46 -07001005 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1006 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001007 hdev->minor_class = cp->minor;
1008
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301009 if (test_bit(HCI_UP, &hdev->flags)) {
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301010 err = update_class(hdev);
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301011 if (err == 0)
1012 err = cmd_complete(sk, index,
1013 MGMT_OP_SET_DEV_CLASS, hdev->dev_class, sizeof(u8)*3);
1014 } else
Szymon Janc4e51eae2011-02-25 19:05:48 +01001015 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001016
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001017 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018 hci_dev_put(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001019
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001020 return err;
1021}
1022
Johan Hedberg03811012010-12-08 00:21:06 +02001023static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1024 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001025{
Johan Hedberg03811012010-12-08 00:21:06 +02001026 struct hci_dev *hdev;
1027 struct mgmt_cp_set_service_cache *cp;
1028 int err;
1029
1030 cp = (void *) data;
1031
1032 if (len != sizeof(*cp))
1033 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
1034
1035 hdev = hci_dev_get(index);
1036 if (!hdev)
1037 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1038
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001039 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001040
1041 BT_DBG("hci%u enable %d", index, cp->enable);
1042
1043 if (cp->enable) {
1044 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1045 err = 0;
1046 } else {
1047 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301048 if (test_bit(HCI_UP, &hdev->flags)) {
1049 err = update_class(hdev);
1050 if (err == 0)
1051 err = update_eir(hdev);
1052 } else
1053 err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02001054 }
1055
1056 if (err == 0)
1057 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1058 0);
1059
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001060 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001061 hci_dev_put(hdev);
1062
1063 return err;
1064}
1065
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001066static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
1067{
1068 struct hci_dev *hdev;
1069 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001071 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001072
1073 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001074
1075 if (len < sizeof(*cp))
1076 return -EINVAL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001077
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001078 key_count = get_unaligned_le16(&cp->key_count);
1079
1080 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001081 if (expected_len > len) {
1082 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1083 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001084 return -EINVAL;
1085 }
1086
Szymon Janc4e51eae2011-02-25 19:05:48 +01001087 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001088 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001089 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001090
Szymon Janc4e51eae2011-02-25 19:05:48 +01001091 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001092 key_count);
1093
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001094 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001095
1096 hci_link_keys_clear(hdev);
1097
1098 set_bit(HCI_LINK_KEYS, &hdev->flags);
1099
1100 if (cp->debug_keys)
1101 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1102 else
1103 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1104
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001105 len -= sizeof(*cp);
1106 i = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001107
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001108 while (i < len) {
1109 struct mgmt_key_info *key = (void *) cp->keys + i;
1110
Brian Gixa68668b2011-08-11 15:49:36 -07001111 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001112
Brian Gixcf956772011-10-20 15:18:51 -07001113 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001114 struct key_master_id *id = (void *) key->data;
1115
1116 if (key->dlen != sizeof(struct key_master_id))
1117 continue;
1118
Brian Gixcf956772011-10-20 15:18:51 -07001119 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1120 key->pin_len, key->auth, id->ediv,
1121 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001122
1123 continue;
1124 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001125
Brian Gixcf956772011-10-20 15:18:51 -07001126 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127 key->pin_len);
1128 }
1129
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001130 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001131
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001132 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001133 hci_dev_put(hdev);
1134
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001135 return err;
1136}
1137
Johan Hedberg03811012010-12-08 00:21:06 +02001138static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001139{
Johan Hedberg03811012010-12-08 00:21:06 +02001140 struct hci_dev *hdev;
1141 struct mgmt_cp_remove_key *cp;
1142 struct hci_conn *conn;
1143 int err;
1144
1145 cp = (void *) data;
1146
1147 if (len != sizeof(*cp))
1148 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1149
1150 hdev = hci_dev_get(index);
1151 if (!hdev)
1152 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
1153
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001154 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001155
1156 err = hci_remove_link_key(hdev, &cp->bdaddr);
1157 if (err < 0) {
1158 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
1159 goto unlock;
1160 }
1161
1162 err = 0;
1163
1164 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1165 goto unlock;
1166
1167 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1168 if (conn) {
1169 struct hci_cp_disconnect dc;
1170
1171 put_unaligned_le16(conn->handle, &dc.handle);
1172 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02001174 }
1175
1176unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001177 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001178 hci_dev_put(hdev);
1179
1180 return err;
1181}
1182
Johan Hedberg8962ee72011-01-20 12:40:27 +02001183static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
1184{
1185 struct hci_dev *hdev;
1186 struct mgmt_cp_disconnect *cp;
1187 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001188 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190 int err;
1191
1192 BT_DBG("");
1193
1194 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001196 if (len != sizeof(*cp))
1197 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1198
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001200 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001201 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001202
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001203 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204
1205 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001206 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001207 goto failed;
1208 }
1209
Szymon Janc4e51eae2011-02-25 19:05:48 +01001210 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1211 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001212 goto failed;
1213 }
1214
1215 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1216 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001217 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1218 if (!conn) {
1219 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1220 ENOTCONN);
1221 goto failed;
1222 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001223 }
1224
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001226 if (!cmd) {
1227 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001228 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001229 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001230
1231 put_unaligned_le16(conn->handle, &dc.handle);
1232 dc.reason = 0x13; /* Remote User Terminated Connection */
1233
1234 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1235 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001236 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001237
1238failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001239 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001240 hci_dev_put(hdev);
1241
1242 return err;
1243}
1244
Szymon Janc8ce62842011-03-01 16:55:32 +01001245static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001247 struct mgmt_rp_get_connections *rp;
1248 struct hci_dev *hdev;
1249 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001250 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001251 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001252 int i, err;
1253
1254 BT_DBG("");
1255
Szymon Janc4e51eae2011-02-25 19:05:48 +01001256 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001257 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001258 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001260 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261
1262 count = 0;
1263 list_for_each(p, &hdev->conn_hash.list) {
1264 count++;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001265 }
1266
Johan Hedberga38528f2011-01-22 06:46:43 +02001267 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1268 rp = kmalloc(rp_len, GFP_ATOMIC);
1269 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001270 err = -ENOMEM;
1271 goto unlock;
1272 }
1273
Johan Hedberg2784eb42011-01-21 13:56:35 +02001274 put_unaligned_le16(count, &rp->conn_count);
1275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 read_lock(&hci_dev_list_lock);
1277
Johan Hedberg2784eb42011-01-21 13:56:35 +02001278 i = 0;
1279 list_for_each(p, &hdev->conn_hash.list) {
1280 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1281
1282 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001283 }
1284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 read_unlock(&hci_dev_list_lock);
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001286
Szymon Janc4e51eae2011-02-25 19:05:48 +01001287 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001288
1289unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001290 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001291 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001292 hci_dev_put(hdev);
1293 return err;
1294}
1295
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1297 u16 len)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001298{
Johan Hedberg980e1a52011-01-22 06:10:07 +02001299 struct hci_dev *hdev;
1300 struct mgmt_cp_pin_code_reply *cp;
1301 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001302 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001303 int err;
1304
1305 BT_DBG("");
1306
1307 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001308
Johan Hedberg980e1a52011-01-22 06:10:07 +02001309 if (len != sizeof(*cp))
1310 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1311
1312 hdev = hci_dev_get(index);
1313 if (!hdev)
1314 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
1315
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001316 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317
1318 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320 goto failed;
1321 }
1322
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001324 if (!cmd) {
1325 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001326 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001327 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328
1329 bacpy(&reply.bdaddr, &cp->bdaddr);
1330 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001332
1333 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1334 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001335 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336
1337failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001338 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339 hci_dev_put(hdev);
1340
1341 return err;
1342}
1343
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301344static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1345 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301347 struct hci_dev *hdev;
1348 struct mgmt_cp_encrypt_link *cp;
1349 struct hci_cp_set_conn_encrypt enc;
1350 struct hci_conn *conn;
1351 int err = 0;
1352
1353 BT_DBG("");
1354
1355 cp = (void *) data;
1356
1357 if (len != sizeof(*cp))
1358 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1359
1360 hdev = hci_dev_get(index);
1361 if (!hdev)
1362 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1363
Brian Gix384ec672012-03-08 18:41:15 -08001364 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301365
1366 if (!test_bit(HCI_UP, &hdev->flags)) {
1367 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001368 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301369 }
1370
Brian Gix384ec672012-03-08 18:41:15 -08001371 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1372 if (!conn) {
1373 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1374 goto done;
1375 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301376
Brian Gix384ec672012-03-08 18:41:15 -08001377 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1378 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1379 goto done;
1380 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301381
1382 if (conn->link_mode & HCI_LM_AUTH) {
1383 enc.handle = cpu_to_le16(conn->handle);
1384 enc.encrypt = cp->enable;
1385 err = hci_send_cmd(hdev,
1386 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1387 } else {
1388 conn->auth_initiator = 1;
1389 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1390 struct hci_cp_auth_requested cp;
1391 cp.handle = cpu_to_le16(conn->handle);
1392 err = hci_send_cmd(conn->hdev,
1393 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1394 }
1395 }
1396
Brian Gix384ec672012-03-08 18:41:15 -08001397done:
1398 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301399 hci_dev_put(hdev);
1400
1401 return err;
1402}
1403
1404
Johan Hedberg980e1a52011-01-22 06:10:07 +02001405static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1406 u16 len)
1407{
1408 struct hci_dev *hdev;
1409 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411 int err;
1412
1413 BT_DBG("");
1414
1415 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001416
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417 if (len != sizeof(*cp))
1418 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1419 EINVAL);
1420
1421 hdev = hci_dev_get(index);
1422 if (!hdev)
1423 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1424 ENODEV);
1425
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001426 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001427
1428 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1430 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001431 goto failed;
1432 }
1433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1435 data, len);
1436 if (!cmd) {
1437 err = -ENOMEM;
1438 goto failed;
1439 }
1440
1441 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1442 &cp->bdaddr);
1443 if (err < 0)
1444 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001445
1446failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001447 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001448 hci_dev_put(hdev);
1449
1450 return err;
1451}
1452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1454 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455{
1456 struct hci_dev *hdev;
1457 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001458
1459 BT_DBG("");
1460
1461 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001463 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001464 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001465
Szymon Janc4e51eae2011-02-25 19:05:48 +01001466 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001467 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001468 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001469
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001470 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001471
1472 hdev->io_capability = cp->io_capability;
1473
1474 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001475 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001476
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001477 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001478 hci_dev_put(hdev);
1479
Szymon Janc4e51eae2011-02-25 19:05:48 +01001480 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001481}
1482
Johan Hedberge9a416b2011-02-19 12:05:56 -03001483static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1484{
1485 struct hci_dev *hdev = conn->hdev;
1486 struct list_head *p;
1487
1488 list_for_each(p, &cmd_list) {
1489 struct pending_cmd *cmd;
1490
1491 cmd = list_entry(p, struct pending_cmd, list);
1492
1493 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1494 continue;
1495
1496 if (cmd->index != hdev->id)
1497 continue;
1498
1499 if (cmd->user_data != conn)
1500 continue;
1501
1502 return cmd;
1503 }
1504
1505 return NULL;
1506}
1507
1508static void pairing_complete(struct pending_cmd *cmd, u8 status)
1509{
1510 struct mgmt_rp_pair_device rp;
1511 struct hci_conn *conn = cmd->user_data;
1512
Brian Gixa68668b2011-08-11 15:49:36 -07001513 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514
Johan Hedberge9a416b2011-02-19 12:05:56 -03001515 bacpy(&rp.bdaddr, &conn->dst);
1516 rp.status = status;
1517
Szymon Janc4e51eae2011-02-25 19:05:48 +01001518 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519
1520 /* So we don't get further callbacks for this connection */
1521 conn->connect_cfm_cb = NULL;
1522 conn->security_cfm_cb = NULL;
1523 conn->disconn_cfm_cb = NULL;
1524
Johan Hedberga664b5b2011-02-19 12:06:02 -03001525 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001526}
1527
1528static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1529{
1530 struct pending_cmd *cmd;
1531
Brian Gixa68668b2011-08-11 15:49:36 -07001532 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001534 cmd = find_pairing(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001535 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001536 BT_DBG("Unable to find a pending command");
Johan Hedberge9a416b2011-02-19 12:05:56 -03001537 return;
1538 }
1539
1540 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001541 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001542}
1543
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001544static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001545{
Johan Hedberge9a416b2011-02-19 12:05:56 -03001546 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001547
1548 BT_DBG(" %u", status);
1549
1550 cmd = find_pairing(conn);
1551 if (!cmd) {
1552 BT_DBG("Unable to find a pending command");
1553 return;
1554 }
1555
1556 if (conn->type == LE_LINK)
1557 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1558 status ? 0 : 1);
1559 else
1560 pairing_complete(cmd, status);
1561}
1562
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001563static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001564{
1565 struct pending_cmd *cmd;
1566
1567 BT_DBG("conn: %p %u", conn, status);
1568
1569 cmd = find_pairing(conn);
1570 if (!cmd) {
1571 BT_DBG("Unable to find a pending command");
1572 return;
1573 }
Brian Gix114f3a62011-09-27 14:02:20 -07001574
1575 if (status)
1576 pairing_complete(cmd, status);
1577
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001578 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001579}
1580
1581static void discovery_terminated(struct pending_cmd *cmd, void *data)
1582{
Brian Gix6e349d02011-11-28 14:51:14 -08001583 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001584 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001585
1586 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001587 hdev = hci_dev_get(cmd->index);
1588 if (!hdev)
1589 goto not_found;
1590
Brian Gix568dde92012-01-11 16:18:04 -08001591 del_timer(&hdev->disco_le_timer);
1592 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001593 hci_dev_put(hdev);
1594
1595not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001596 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1597
1598 list_del(&cmd->list);
1599
1600 mgmt_pending_free(cmd);
1601}
1602
Johan Hedberge9a416b2011-02-19 12:05:56 -03001603static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
1604{
1605 struct hci_dev *hdev;
1606 struct mgmt_cp_pair_device *cp;
1607 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001608 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001609 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001610 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001611 int err;
1612
1613 BT_DBG("");
1614
Brian Gix64bd5302011-09-08 11:35:48 -07001615 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001616
Brian Gix64bd5302011-09-08 11:35:48 -07001617 if (len != sizeof(*cp))
1618 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1619
Johan Hedberge9a416b2011-02-19 12:05:56 -03001620 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001621
Johan Hedberge9a416b2011-02-19 12:05:56 -03001622 if (!hdev)
1623 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
1624
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001625 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001626
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301627 io_cap = cp->io_cap;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001628
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001629 sec_level = BT_SECURITY_MEDIUM;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301630 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001631
Brian Gixfdd38922011-09-28 16:23:48 -07001632 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1633 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001634 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1635 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001636 } else {
1637 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1638 if (io_cap == 0x04)
1639 io_cap = 0x01;
1640 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1641 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301642 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001643 }
Johan Hedberg1425acb2011-11-11 00:07:35 +02001644
Ville Tervo30e76272011-02-22 16:10:53 -03001645 if (IS_ERR(conn)) {
1646 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001647 goto unlock;
1648 }
1649
1650 if (conn->connect_cfm_cb) {
1651 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001652 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001653 goto unlock;
1654 }
1655
Szymon Janc4e51eae2011-02-25 19:05:48 +01001656 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001657 if (!cmd) {
1658 err = -ENOMEM;
1659 hci_conn_put(conn);
1660 goto unlock;
1661 }
1662
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001663 conn->connect_cfm_cb = pairing_connect_complete_cb;
1664 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001665 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001666 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001667 cmd->user_data = conn;
1668
1669 if (conn->state == BT_CONNECTED &&
1670 hci_conn_security(conn, sec_level, auth_type))
1671 pairing_complete(cmd, 0);
1672
1673 err = 0;
1674
1675unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001676 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001677 hci_dev_put(hdev);
1678
1679 return err;
1680}
1681
Szymon Janc4e51eae2011-02-25 19:05:48 +01001682static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001683 u16 len, u16 opcode)
Johan Hedberg28424702012-02-02 04:02:29 +02001684{
Johan Hedberga5c29682011-02-19 12:05:57 -03001685 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001686 u16 mgmt_op = opcode, hci_op;
Johan Hedberg28424702012-02-02 04:02:29 +02001687 struct pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03001688 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001689 struct hci_conn *le_conn;
Johan Hedberg28424702012-02-02 04:02:29 +02001690 int err;
1691
Brian Gixa68668b2011-08-11 15:49:36 -07001692 BT_DBG("%d", mgmt_op);
Johan Hedberg28424702012-02-02 04:02:29 +02001693
Brian Gixa68668b2011-08-11 15:49:36 -07001694 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001695 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Johan Hedberg272d90d2012-02-09 15:26:12 +02001696 else
Brian Gixa68668b2011-08-11 15:49:36 -07001697 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Brian Gix47c15e22011-11-16 13:53:14 -08001698
Brian Gixa68668b2011-08-11 15:49:36 -07001699 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001700 return cmd_status(sk, index, mgmt_op, EINVAL);
1701
Szymon Janc4e51eae2011-02-25 19:05:48 +01001702 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001703 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001704 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001705
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001706 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001707
Johan Hedberga5c29682011-02-19 12:05:57 -03001708 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001709 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberg272d90d2012-02-09 15:26:12 +02001710 goto done;
1711 }
1712
Brian Gixa68668b2011-08-11 15:49:36 -07001713 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1714 if (le_conn) {
1715 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
Brian Gix47c15e22011-11-16 13:53:14 -08001716 goto done;
1717 }
Brian Gixa68668b2011-08-11 15:49:36 -07001718 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1719 "Reject" : "Accept");
Brian Gix47c15e22011-11-16 13:53:14 -08001720
Szymon Janc4e51eae2011-02-25 19:05:48 +01001721 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001722 if (!cmd) {
1723 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001724 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001725 }
1726
Brian Gixa68668b2011-08-11 15:49:36 -07001727 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001728 if (err < 0)
1729 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001730
Brian Gix0df4c182011-11-16 13:53:13 -08001731done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001732 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001733 hci_dev_put(hdev);
1734
Johan Hedberga5c29682011-02-19 12:05:57 -03001735 return err;
1736}
1737
Brian Gixa68668b2011-08-11 15:49:36 -07001738static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1739 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08001740{
Brian Gixa68668b2011-08-11 15:49:36 -07001741 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1742 struct hci_cp_remote_name_req hci_cp;
1743 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001744 struct pending_cmd *cmd;
1745 int err;
1746
1747 BT_DBG("");
1748
Brian Gixa68668b2011-08-11 15:49:36 -07001749 if (len != sizeof(*mgmt_cp))
1750 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001751
Brian Gixa68668b2011-08-11 15:49:36 -07001752 hdev = hci_dev_get(index);
1753 if (!hdev)
1754 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001755
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001756 hci_dev_lock_bh(hdev);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001757
Brian Gixa68668b2011-08-11 15:49:36 -07001758 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001759 if (!cmd) {
1760 err = -ENOMEM;
1761 goto failed;
1762 }
1763
Brian Gixa68668b2011-08-11 15:49:36 -07001764 memset(&hci_cp, 0, sizeof(hci_cp));
1765 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1766 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1767 &hci_cp);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001768 if (err < 0)
1769 mgmt_pending_remove(cmd);
1770
1771failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001772 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001773 hci_dev_put(hdev);
1774
Johan Hedbergb312b1612011-03-16 14:29:37 +02001775 return err;
1776}
1777
Brian Gix7f7e16c2011-11-01 16:27:25 -07001778static int set_connection_params(struct sock *sk, u16 index,
1779 unsigned char *data, u16 len)
Szymon Jancc35938b2011-03-22 13:12:21 +01001780{
Brian Gix7f7e16c2011-11-01 16:27:25 -07001781 struct mgmt_cp_set_connection_params *cp = (void *) data;
1782 struct hci_dev *hdev;
1783 struct hci_conn *conn;
1784 int err;
1785
1786 BT_DBG("");
1787
1788 if (len != sizeof(*cp))
1789 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1790 EINVAL);
1791
1792 hdev = hci_dev_get(index);
1793 if (!hdev)
1794 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1795 ENODEV);
1796
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001797 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001798
1799 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1800 if (!conn) {
1801 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1802 ENOTCONN);
1803 goto failed;
1804 }
1805
1806 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1807 le16_to_cpu(cp->interval_max),
1808 le16_to_cpu(cp->slave_latency),
1809 le16_to_cpu(cp->timeout_multiplier));
1810
1811 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1812
1813failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001814 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001815 hci_dev_put(hdev);
1816
1817 return err;
1818}
1819
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001820static int set_rssi_reporter(struct sock *sk, u16 index,
1821 unsigned char *data, u16 len)
1822{
1823 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
1824 struct hci_dev *hdev;
1825 struct hci_conn *conn;
1826 int err = 0;
1827
1828 if (len != sizeof(*cp))
1829 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1830 EINVAL);
1831
1832 hdev = hci_dev_get(index);
1833 if (!hdev)
1834 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1835 ENODEV);
1836
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001837 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001838
1839 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1840
1841 if (!conn) {
1842 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1843 ENOTCONN);
1844 goto failed;
1845 }
1846
1847 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
1848 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
1849 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
1850
1851failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001852 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001853 hci_dev_put(hdev);
1854
1855 return err;
1856}
1857
1858static int unset_rssi_reporter(struct sock *sk, u16 index,
1859 unsigned char *data, u16 len)
1860{
1861 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
1862 struct hci_dev *hdev;
1863 struct hci_conn *conn;
1864 int err = 0;
1865
1866 if (len != sizeof(*cp))
1867 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1868 EINVAL);
1869
1870 hdev = hci_dev_get(index);
1871
1872 if (!hdev)
1873 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1874 ENODEV);
1875
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001876 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001877
1878 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1879
1880 if (!conn) {
1881 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1882 ENOTCONN);
1883 goto failed;
1884 }
1885
1886 hci_conn_unset_rssi_reporter(conn);
1887
1888failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001889 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001890 hci_dev_put(hdev);
1891
1892 return err;
1893}
1894
Johan Hedberg03811012010-12-08 00:21:06 +02001895static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1896 u16 len)
1897{
1898 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1899 struct hci_cp_write_local_name hci_cp;
1900 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01001901 struct pending_cmd *cmd;
1902 int err;
1903
Johan Hedberg03811012010-12-08 00:21:06 +02001904 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01001905
Johan Hedberg03811012010-12-08 00:21:06 +02001906 if (len != sizeof(*mgmt_cp))
1907 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01001908
Johan Hedberg03811012010-12-08 00:21:06 +02001909 hdev = hci_dev_get(index);
1910 if (!hdev)
1911 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1912
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001913 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001914
1915 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1916 if (!cmd) {
1917 err = -ENOMEM;
1918 goto failed;
1919 }
1920
1921 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1922 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1923 &hci_cp);
1924 if (err < 0)
1925 mgmt_pending_remove(cmd);
1926
1927failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001928 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001929 hci_dev_put(hdev);
1930
1931 return err;
1932}
1933
Brian Gixa68668b2011-08-11 15:49:36 -07001934static void discovery_rsp(struct pending_cmd *cmd, void *data)
1935{
1936 struct mgmt_mode ev;
1937
1938 BT_DBG("");
1939 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1940 ev.val = 1;
1941 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1942 } else {
1943 ev.val = 0;
1944 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1945 NULL, 0);
1946 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001947 struct hci_dev *hdev = hci_dev_get(cmd->index);
1948 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08001949 del_timer(&hdev->disco_le_timer);
1950 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001951 hci_dev_put(hdev);
1952 }
Brian Gixa68668b2011-08-11 15:49:36 -07001953 }
1954 }
1955
1956 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1957
1958 list_del(&cmd->list);
1959
1960 mgmt_pending_free(cmd);
1961}
1962
1963void mgmt_inquiry_started(u16 index)
1964{
1965 BT_DBG("");
1966 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1967 discovery_rsp, NULL);
1968}
1969
1970void mgmt_inquiry_complete_evt(u16 index, u8 status)
1971{
1972 struct hci_dev *hdev;
1973 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08001974 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001975 int err = -1;
1976
1977 BT_DBG("");
1978
1979 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001980
Brian Gixa68668b2011-08-11 15:49:36 -07001981 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07001982
1983 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1984 discovery_terminated, NULL);
1985
1986 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001987
Brian Gix64bd5302011-09-08 11:35:48 -07001988 if (hdev)
1989 goto done;
1990 else
1991 return;
1992 }
Brian Gixa68668b2011-08-11 15:49:36 -07001993
Brian Gix568dde92012-01-11 16:18:04 -08001994 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07001995 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1996 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08001997 if (err >= 0) {
1998 mod_timer(&hdev->disco_le_timer, jiffies +
1999 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2000 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002001 } else
Brian Gix568dde92012-01-11 16:18:04 -08002002 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002003 }
2004
Brian Gix568dde92012-01-11 16:18:04 -08002005 if (hdev->disco_state == SCAN_IDLE)
2006 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2007
Brian Gixa68668b2011-08-11 15:49:36 -07002008 if (err < 0)
2009 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2010 discovery_terminated, NULL);
2011
Brian Gix64bd5302011-09-08 11:35:48 -07002012done:
Brian Gixa68668b2011-08-11 15:49:36 -07002013 hci_dev_put(hdev);
2014}
2015
Brian Gix568dde92012-01-11 16:18:04 -08002016void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002017{
Brian Gix568dde92012-01-11 16:18:04 -08002018 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002019 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002020 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002021
Brian Gix568dde92012-01-11 16:18:04 -08002022 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002023
Brian Gix568dde92012-01-11 16:18:04 -08002024 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002025
Brian Gix568dde92012-01-11 16:18:04 -08002026 if (!hdev)
2027 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002028
Brian Gix568dde92012-01-11 16:18:04 -08002029 hci_dev_lock_bh(hdev);
2030 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002031
Brian Gix568dde92012-01-11 16:18:04 -08002032 if (hdev->disco_state != SCAN_IDLE) {
2033 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002034
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302035 if (test_bit(HCI_UP, &hdev->flags)) {
2036 if (hdev->disco_state == SCAN_LE)
2037 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002038 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302039 else
2040 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2041 NULL);
2042 }
Brian Gix568dde92012-01-11 16:18:04 -08002043 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002044 }
Brian Gix568dde92012-01-11 16:18:04 -08002045
2046 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2047
2048 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2049 if (cmd)
2050 mgmt_pending_remove(cmd);
2051
2052 hci_dev_unlock_bh(hdev);
2053 hci_dev_put(hdev);
2054}
2055
2056void mgmt_disco_le_timeout(unsigned long data)
2057{
2058 struct hci_dev *hdev = (void *)data;
2059 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2060
2061 BT_DBG("hci%d", hdev->id);
2062
2063 hdev = hci_dev_get(hdev->id);
2064
2065 if (!hdev)
2066 return;
2067
2068 hci_dev_lock_bh(hdev);
2069
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302070 if (test_bit(HCI_UP, &hdev->flags)) {
2071 if (hdev->disco_state == SCAN_LE)
2072 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2073 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002074
2075 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302076 if (hdev->disco_state != SCAN_IDLE) {
2077 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2078 hdev->disco_int_phase *= 2;
2079 hdev->disco_int_count = 0;
2080 cp.num_rsp = (u8) hdev->disco_int_phase;
2081 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2082 hdev->disco_state = SCAN_BR;
2083 }
Brian Gix568dde92012-01-11 16:18:04 -08002084 }
2085
2086 hci_dev_unlock_bh(hdev);
2087 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002088}
2089
2090static int start_discovery(struct sock *sk, u16 index)
2091{
2092 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2093 struct hci_dev *hdev;
2094 struct pending_cmd *cmd;
2095 int err;
2096
2097 BT_DBG("");
2098
2099 hdev = hci_dev_get(index);
2100 if (!hdev)
2101 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2102
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002103 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002104
Brian Gix568dde92012-01-11 16:18:04 -08002105 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2106 err = -EBUSY;
2107 goto failed;
2108 }
2109
Brian Gixa68668b2011-08-11 15:49:36 -07002110 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2111 if (!cmd) {
2112 err = -ENOMEM;
2113 goto failed;
2114 }
2115
2116 /* If LE Capable, we will alternate between BR/EDR and LE */
2117 if (lmp_le_capable(hdev)) {
2118 struct hci_cp_le_set_scan_parameters le_cp;
2119
2120 /* Shorten BR scan params */
2121 cp.num_rsp = 1;
2122 cp.length /= 2;
2123
2124 /* Setup LE scan params */
2125 memset(&le_cp, 0, sizeof(le_cp));
2126 le_cp.type = 0x01; /* Active scanning */
2127 /* The recommended value for scan interval and window is
2128 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2129 le_cp.interval = cpu_to_le16(0x0012);
2130 le_cp.window = cpu_to_le16(0x0012);
2131 le_cp.own_bdaddr_type = 0; /* Public address */
2132 le_cp.filter = 0; /* Accept all adv packets */
2133
2134 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2135 sizeof(le_cp), &le_cp);
2136 }
2137
2138 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2139
Bhasker Neti09760742012-05-25 12:30:39 +05302140 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002141 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302142 hdev->disco_state = SCAN_IDLE;
2143 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002144 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2145 if (!cmd)
2146 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2147 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002148 hdev->disco_int_phase = 1;
2149 hdev->disco_int_count = 0;
2150 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002151 del_timer(&hdev->disco_le_timer);
2152 del_timer(&hdev->disco_timer);
2153 mod_timer(&hdev->disco_timer,
2154 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302155 } else
2156 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002157
2158failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002159 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002160 hci_dev_put(hdev);
2161
Brian Gix568dde92012-01-11 16:18:04 -08002162 if (err < 0)
2163 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2164
Brian Gixa68668b2011-08-11 15:49:36 -07002165 return err;
2166}
2167
2168static int stop_discovery(struct sock *sk, u16 index)
2169{
2170 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2171 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002172 struct hci_dev *hdev;
2173 struct pending_cmd *cmd = NULL;
2174 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002175 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002176
2177 BT_DBG("");
2178
2179 hdev = hci_dev_get(index);
2180 if (!hdev)
2181 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2182
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002183 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002184
Brian Gix568dde92012-01-11 16:18:04 -08002185 state = hdev->disco_state;
2186 hdev->disco_state = SCAN_IDLE;
2187 del_timer(&hdev->disco_le_timer);
2188 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002189
Brian Gix568dde92012-01-11 16:18:04 -08002190 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002191 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2192 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002193 if (err >= 0) {
2194 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2195 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002196
Brian Gix568dde92012-01-11 16:18:04 -08002197 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2198 NULL, 0);
2199 }
Bhasker Neti09760742012-05-25 12:30:39 +05302200 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002201 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002202
Brian Gix568dde92012-01-11 16:18:04 -08002203 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002204 if (err < 0 && cmd)
2205 mgmt_pending_remove(cmd);
2206
2207 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2208
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002209 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002210 hci_dev_put(hdev);
2211
2212 if (err < 0)
2213 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2214 else
2215 return err;
2216}
2217
Szymon Jancc35938b2011-03-22 13:12:21 +01002218static int read_local_oob_data(struct sock *sk, u16 index)
2219{
2220 struct hci_dev *hdev;
2221 struct pending_cmd *cmd;
2222 int err;
2223
2224 BT_DBG("hci%u", index);
2225
2226 hdev = hci_dev_get(index);
2227 if (!hdev)
2228 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2229 ENODEV);
2230
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002231 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002232
2233 if (!test_bit(HCI_UP, &hdev->flags)) {
2234 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2235 ENETDOWN);
2236 goto unlock;
2237 }
2238
2239 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2240 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2241 EOPNOTSUPP);
2242 goto unlock;
2243 }
2244
2245 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2246 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2247 goto unlock;
2248 }
2249
2250 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2251 if (!cmd) {
2252 err = -ENOMEM;
2253 goto unlock;
2254 }
2255
2256 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2257 if (err < 0)
2258 mgmt_pending_remove(cmd);
2259
2260unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002261 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002262 hci_dev_put(hdev);
2263
2264 return err;
2265}
2266
Szymon Janc2763eda2011-03-22 13:12:22 +01002267static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2268 u16 len)
2269{
2270 struct hci_dev *hdev;
2271 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2272 int err;
2273
2274 BT_DBG("hci%u ", index);
2275
2276 if (len != sizeof(*cp))
2277 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2278 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002279
Szymon Janc2763eda2011-03-22 13:12:22 +01002280 hdev = hci_dev_get(index);
2281 if (!hdev)
2282 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2283 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002284
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002285 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002286
2287 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2288 cp->randomizer);
2289 if (err < 0)
2290 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2291 else
2292 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2293 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002294
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002295 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002296 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002297
Szymon Janc2763eda2011-03-22 13:12:22 +01002298 return err;
2299}
2300
2301static int remove_remote_oob_data(struct sock *sk, u16 index,
2302 unsigned char *data, u16 len)
2303{
2304 struct hci_dev *hdev;
2305 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2306 int err;
2307
2308 BT_DBG("hci%u ", index);
2309
2310 if (len != sizeof(*cp))
2311 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2312 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002313
Szymon Janc2763eda2011-03-22 13:12:22 +01002314 hdev = hci_dev_get(index);
2315 if (!hdev)
2316 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2317 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002318
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002319 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002320
2321 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2322 if (err < 0)
2323 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2324 -err);
2325 else
2326 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2327 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002328
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002329 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002330 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002331
2332 return err;
2333}
2334
Johan Hedberg03811012010-12-08 00:21:06 +02002335int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2336{
2337 unsigned char *buf;
2338 struct mgmt_hdr *hdr;
2339 u16 opcode, index, len;
2340 int err;
2341
2342 BT_DBG("got %zu bytes", msglen);
2343
2344 if (msglen < sizeof(*hdr))
2345 return -EINVAL;
2346
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002347 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002348 if (!buf)
2349 return -ENOMEM;
2350
2351 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2352 err = -EFAULT;
2353 goto done;
2354 }
2355
2356 hdr = (struct mgmt_hdr *) buf;
2357 opcode = get_unaligned_le16(&hdr->opcode);
2358 index = get_unaligned_le16(&hdr->index);
2359 len = get_unaligned_le16(&hdr->len);
2360
2361 if (len != msglen - sizeof(*hdr)) {
2362 err = -EINVAL;
2363 goto done;
2364 }
2365
Brian Gixa68668b2011-08-11 15:49:36 -07002366 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002367 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002368 case MGMT_OP_READ_VERSION:
2369 err = read_version(sk);
2370 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002371 case MGMT_OP_READ_INDEX_LIST:
2372 err = read_index_list(sk);
2373 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002374 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002375 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002376 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002377 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002378 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002379 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002380 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002381 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002382 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002383 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2384 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2385 len);
2386 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002387 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002388 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002389 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002390 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002391 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002392 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002393 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002394 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002395 break;
2396 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002397 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002398 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002399 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002400 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002401 break;
2402 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002403 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002404 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002405 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002406 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002407 break;
2408 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002409 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002410 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002412 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002413 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002414 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002415 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002416 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002417 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002418 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002419 break;
2420 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002421 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002422 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002423 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002424 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002425 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002426 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002427 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002428 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002429 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002430 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002431 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002432 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2433 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002434 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002435 case MGMT_OP_SET_LOCAL_NAME:
2436 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2437 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002438 case MGMT_OP_START_DISCOVERY:
2439 err = start_discovery(sk, index);
2440 break;
2441 case MGMT_OP_STOP_DISCOVERY:
2442 err = stop_discovery(sk, index);
2443 break;
2444 case MGMT_OP_RESOLVE_NAME:
2445 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2446 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002447 case MGMT_OP_SET_CONNECTION_PARAMS:
2448 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2449 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002450 case MGMT_OP_SET_RSSI_REPORTER:
2451 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2452 break;
2453 case MGMT_OP_UNSET_RSSI_REPORTER:
2454 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2455 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002456 case MGMT_OP_READ_LOCAL_OOB_DATA:
2457 err = read_local_oob_data(sk, index);
2458 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002459 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2460 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2461 break;
2462 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2463 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2464 len);
2465 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302466 case MGMT_OP_ENCRYPT_LINK:
2467 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2468 break;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002469
Johan Hedberg03811012010-12-08 00:21:06 +02002470 default:
2471 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002472 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002473 break;
2474 }
2475
Johan Hedberge41d8b42010-12-13 21:07:03 +02002476 if (err < 0)
2477 goto done;
2478
Johan Hedberg03811012010-12-08 00:21:06 +02002479 err = msglen;
2480
2481done:
2482 kfree(buf);
2483 return err;
2484}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002485
Johan Hedbergb24752f2011-11-03 14:40:33 +02002486static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2487{
2488 u8 *status = data;
2489
2490 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2491 mgmt_pending_remove(cmd);
2492}
2493
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002494int mgmt_index_added(u16 index)
2495{
Brian Gixa68668b2011-08-11 15:49:36 -07002496 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002497 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002498}
2499
2500int mgmt_index_removed(u16 index)
2501{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002502 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002503
Brian Gixa68668b2011-08-11 15:49:36 -07002504 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002505
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002506 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2507
Szymon Janc4e51eae2011-02-25 19:05:48 +01002508 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002509}
2510
Johan Hedberg73f22f62010-12-29 16:00:25 +02002511struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002512 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002513 struct sock *sk;
2514};
2515
Johan Hedberg72a734e2010-12-30 00:38:22 +02002516static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002517{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002518 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002519 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002520
Johan Hedberg72a734e2010-12-30 00:38:22 +02002521 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002522 return;
2523
Johan Hedberg053f0212011-01-26 13:07:10 +02002524 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002525
2526 list_del(&cmd->list);
2527
2528 if (match->sk == NULL) {
2529 match->sk = cmd->sk;
2530 sock_hold(match->sk);
2531 }
2532
2533 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002534}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002535
2536int mgmt_powered(u16 index, u8 powered)
2537{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002538 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002539 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002540 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002541
Brian Gixa68668b2011-08-11 15:49:36 -07002542 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002543
Johan Hedberg72a734e2010-12-30 00:38:22 +02002544 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002545
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002546 if (!powered) {
2547 u8 status = ENETDOWN;
2548 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002549 }
2550
Johan Hedberg72a734e2010-12-30 00:38:22 +02002551 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002552
Szymon Janc4e51eae2011-02-25 19:05:48 +01002553 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002554
2555 if (match.sk)
2556 sock_put(match.sk);
2557
2558 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002559}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002560
Johan Hedberg73f22f62010-12-29 16:00:25 +02002561int mgmt_discoverable(u16 index, u8 discoverable)
2562{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002563 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002564 struct cmd_lookup match = { discoverable, NULL };
2565 int ret;
2566
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002567 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002568
Johan Hedberg73f22f62010-12-29 16:00:25 +02002569 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002570
Szymon Janc4e51eae2011-02-25 19:05:48 +01002571 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2572 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002573
Johan Hedberg73f22f62010-12-29 16:00:25 +02002574 if (match.sk)
2575 sock_put(match.sk);
2576
2577 return ret;
2578}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002579
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002580int mgmt_connectable(u16 index, u8 connectable)
2581{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002582 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002583 struct cmd_lookup match = { connectable, NULL };
2584 int ret;
2585
Johan Hedberg72a734e2010-12-30 00:38:22 +02002586 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002587
Johan Hedberg03811012010-12-08 00:21:06 +02002588 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002589
Szymon Janc4e51eae2011-02-25 19:05:48 +01002590 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002591
2592 if (match.sk)
2593 sock_put(match.sk);
2594
2595 return ret;
2596}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002597
Brian Gixa68668b2011-08-11 15:49:36 -07002598int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002599{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002600 struct mgmt_ev_new_key *ev;
2601 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002602
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002603 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2604 ev = kzalloc(total, GFP_ATOMIC);
2605 if (!ev)
2606 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002607
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002608 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002609 ev->key.addr_type = key->addr_type;
2610 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002611 memcpy(ev->key.val, key->val, 16);
2612 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002613 ev->key.auth = key->auth;
2614 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002615 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002616
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002617 memcpy(ev->key.data, key->data, key->dlen);
2618
2619 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2620
2621 kfree(ev);
2622
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002623 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002624}
2625
Brian Gix2e2f50d2011-09-13 12:36:04 -07002626int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002627{
Johan Hedbergf7520542011-01-20 12:34:39 +02002628 struct mgmt_ev_connected ev;
Johan Hedbergca69b792011-11-11 18:10:00 +02002629
Johan Hedbergf7520542011-01-20 12:34:39 +02002630 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002631 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002632
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002634}
2635
Johan Hedberg8962ee72011-01-20 12:40:27 +02002636static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2637{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002638 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002639 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002640 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002641
Johan Hedberga38528f2011-01-22 06:46:43 +02002642 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002643
Szymon Janc4e51eae2011-02-25 19:05:48 +01002644 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002645
2646 *sk = cmd->sk;
2647 sock_hold(*sk);
2648
Johan Hedberga664b5b2011-02-19 12:06:02 -03002649 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002650}
2651
Johan Hedbergf7520542011-01-20 12:34:39 +02002652int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002653{
Johan Hedbergf7520542011-01-20 12:34:39 +02002654 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002655 struct sock *sk = NULL;
2656 int err;
2657
2658 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002659
Johan Hedbergf7520542011-01-20 12:34:39 +02002660 bacpy(&ev.bdaddr, bdaddr);
2661
Szymon Janc4e51eae2011-02-25 19:05:48 +01002662 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002663
2664 if (sk)
2665 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002666
Johan Hedberg8962ee72011-01-20 12:40:27 +02002667 return err;
2668}
2669
2670int mgmt_disconnect_failed(u16 index)
2671{
2672 struct pending_cmd *cmd;
2673 int err;
2674
2675 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2676 if (!cmd)
2677 return -ENOENT;
2678
Szymon Janc4e51eae2011-02-25 19:05:48 +01002679 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002680
Johan Hedberga664b5b2011-02-19 12:06:02 -03002681 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002682
2683 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002684}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002685
2686int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2687{
2688 struct mgmt_ev_connect_failed ev;
2689
Johan Hedberg17d5c042011-01-22 06:09:08 +02002690 bacpy(&ev.bdaddr, bdaddr);
2691 ev.status = status;
2692
Szymon Janc4e51eae2011-02-25 19:05:48 +01002693 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002694}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002697{
2698 struct mgmt_ev_pin_code_request ev;
2699
Brian Gixa68668b2011-08-11 15:49:36 -07002700 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701
Johan Hedberg980e1a52011-01-22 06:10:07 +02002702 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002703 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002704
Szymon Janc4e51eae2011-02-25 19:05:48 +01002705 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2706 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002707}
2708
2709int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2710{
2711 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002712 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713 int err;
2714
2715 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2716 if (!cmd)
2717 return -ENOENT;
2718
Johan Hedbergac56fb12011-02-19 12:05:59 -03002719 bacpy(&rp.bdaddr, bdaddr);
2720 rp.status = status;
2721
Szymon Janc4e51eae2011-02-25 19:05:48 +01002722 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2723 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002724
Johan Hedberga664b5b2011-02-19 12:06:02 -03002725 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726
2727 return err;
2728}
2729
2730int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2731{
2732 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002733 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002734 int err;
2735
2736 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2737 if (!cmd)
2738 return -ENOENT;
2739
Johan Hedbergac56fb12011-02-19 12:05:59 -03002740 bacpy(&rp.bdaddr, bdaddr);
2741 rp.status = status;
2742
Szymon Janc4e51eae2011-02-25 19:05:48 +01002743 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2744 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002745
Johan Hedberga664b5b2011-02-19 12:06:02 -03002746 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002747
2748 return err;
2749}
Johan Hedberga5c29682011-02-19 12:05:57 -03002750
Brian Gixa68668b2011-08-11 15:49:36 -07002751int mgmt_user_confirm_request(u16 index, u8 event,
2752 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002753{
2754 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002755 struct hci_conn *conn = NULL;
2756 struct hci_dev *hdev;
2757 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03002758
Brian Gixa68668b2011-08-11 15:49:36 -07002759 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002760
Brian Gixa68668b2011-08-11 15:49:36 -07002761 hdev = hci_dev_get(index);
2762
Brian Gix64bd5302011-09-08 11:35:48 -07002763 if (!hdev)
2764 return -ENODEV;
2765
Brian Gix64bd5302011-09-08 11:35:48 -07002766 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002767
2768 ev.auto_confirm = 0;
2769
2770 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2771 goto no_auto_confirm;
2772
2773 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2774 rem_cap = conn->remote_cap;
2775 loc_mitm = conn->auth_type & 0x01;
2776 rem_mitm = conn->remote_auth & 0x01;
2777
Brian Gixdbf59292011-11-11 15:45:17 -08002778 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2779 conn->auth_initiator && rem_cap == 0x03)
2780 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302781 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
2782 if (!loc_mitm && !rem_mitm)
2783 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07002784 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302785 }
Brian Gixa68668b2011-08-11 15:49:36 -07002786
2787
2788 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2789 ev.auto_confirm = 1;
2790
2791no_auto_confirm:
2792 bacpy(&ev.bdaddr, bdaddr);
2793 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03002794 put_unaligned_le32(value, &ev.value);
2795
Brian Gix64bd5302011-09-08 11:35:48 -07002796 hci_dev_put(hdev);
2797
Brian Gixa68668b2011-08-11 15:49:36 -07002798 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2799 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002800}
2801
Brian Gixa68668b2011-08-11 15:49:36 -07002802int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08002803{
2804 struct mgmt_ev_user_passkey_request ev;
2805
Johan Hedberga5c29682011-02-19 12:05:57 -03002806 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08002807
Johan Hedberga5c29682011-02-19 12:05:57 -03002808 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002809
Brian Gixa68668b2011-08-11 15:49:36 -07002810 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03002811 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08002812}
2813
Johan Hedberga5c29682011-02-19 12:05:57 -03002814static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2815 u8 opcode)
2816{
2817 struct pending_cmd *cmd;
2818 struct mgmt_rp_user_confirm_reply rp;
2819 int err;
2820
2821 cmd = mgmt_pending_find(opcode, index);
2822 if (!cmd)
2823 return -ENOENT;
2824
Johan Hedberga5c29682011-02-19 12:05:57 -03002825 bacpy(&rp.bdaddr, bdaddr);
2826 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002827 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002828
Johan Hedberga664b5b2011-02-19 12:06:02 -03002829 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002830
2831 return err;
2832}
2833
2834int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2835{
2836 return confirm_reply_complete(index, bdaddr, status,
2837 MGMT_OP_USER_CONFIRM_REPLY);
2838}
2839
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002840int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002841{
2842 return confirm_reply_complete(index, bdaddr, status,
2843 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2844}
Johan Hedberg2a611692011-02-19 12:06:00 -03002845
2846int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2847{
2848 struct mgmt_ev_auth_failed ev;
2849
Johan Hedberg2a611692011-02-19 12:06:00 -03002850 bacpy(&ev.bdaddr, bdaddr);
2851 ev.status = status;
2852
Szymon Janc4e51eae2011-02-25 19:05:48 +01002853 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002854}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002855
2856int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2857{
2858 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002859 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002860 struct mgmt_cp_set_local_name ev;
2861 int err;
2862
2863 memset(&ev, 0, sizeof(ev));
2864 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2865
2866 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2867 if (!cmd)
2868 goto send_event;
2869
2870 if (status) {
2871 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2872 goto failed;
2873 }
2874
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002875 hdev = hci_dev_get(index);
2876 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002877 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002878 hci_dev_put(hdev);
2879 }
2880
Johan Hedbergb312b1612011-03-16 14:29:37 +02002881 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2882 sizeof(ev));
2883 if (err < 0)
2884 goto failed;
2885
2886send_event:
2887 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2888 cmd ? cmd->sk : NULL);
2889
2890failed:
2891 if (cmd)
2892 mgmt_pending_remove(cmd);
2893 return err;
2894}
Szymon Jancc35938b2011-03-22 13:12:21 +01002895
2896int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2897 u8 status)
2898{
2899 struct pending_cmd *cmd;
2900 int err;
2901
2902 BT_DBG("hci%u status %u", index, status);
2903
2904 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2905 if (!cmd)
2906 return -ENOENT;
2907
2908 if (status) {
2909 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2910 EIO);
2911 } else {
2912 struct mgmt_rp_read_local_oob_data rp;
2913
2914 memcpy(rp.hash, hash, sizeof(rp.hash));
2915 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2916
2917 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2918 &rp, sizeof(rp));
2919 }
2920
2921 mgmt_pending_remove(cmd);
2922
2923 return err;
2924}
Johan Hedberge17acd42011-03-30 23:57:16 +03002925
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002926void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
2927 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002928{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002929 struct mgmt_ev_rssi_update ev;
2930 struct hci_conn *conn;
2931 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002932
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002933 if (status)
2934 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002935
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002936 hdev = hci_dev_get(index);
2937 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002938
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002939 if (!conn)
2940 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002941
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002942 BT_DBG("rssi_update_thresh_exceed : %d ",
2943 conn->rssi_update_thresh_exceed);
2944 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
2945 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002946
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002947 if (conn->rssi_update_thresh_exceed == 1) {
2948 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002949 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002950 memset(&ev, 0, sizeof(ev));
2951 bacpy(&ev.bdaddr, bdaddr);
2952 ev.rssi = rssi;
2953 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2954 sizeof(ev), NULL);
2955 } else {
2956 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2957 conn->rssi_update_interval,
2958 conn->rssi_update_thresh_exceed);
2959 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002960 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002961 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002962 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002963 memset(&ev, 0, sizeof(ev));
2964 bacpy(&ev.bdaddr, bdaddr);
2965 ev.rssi = rssi;
2966 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2967 sizeof(ev), NULL);
2968 } else {
2969 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2970 conn->rssi_update_interval,
2971 conn->rssi_update_thresh_exceed);
2972 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002973 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002974}
2975
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002976
Brian Gixa68668b2011-08-11 15:49:36 -07002977int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2978 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002979{
2980 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08002981 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02002982 int err;
2983
Brian Gixa68668b2011-08-11 15:49:36 -07002984 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002985
Johan Hedbergf963e8e2012-02-20 23:30:44 +02002986 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02002987
Johan Hedberge17acd42011-03-30 23:57:16 +03002988 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002989 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002990 ev.type = type;
2991 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002992
Brian Gixa68668b2011-08-11 15:49:36 -07002993 if (dev_class)
2994 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002995
Brian Gixa68668b2011-08-11 15:49:36 -07002996 if (eir && eir_len)
2997 memcpy(ev.eir, eir, eir_len);
2998
2999 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3000
3001 if (err < 0)
3002 return err;
3003
Brian Gix568dde92012-01-11 16:18:04 -08003004 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003005
Brian Gix568dde92012-01-11 16:18:04 -08003006 if (!hdev)
3007 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003008
Brian Gix568dde92012-01-11 16:18:04 -08003009 if (hdev->disco_state == SCAN_IDLE)
3010 goto done;
3011
3012 hdev->disco_int_count++;
3013
3014 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3015 /* Inquiry scan for General Discovery LAP */
3016 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3017 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3018
3019 hdev->disco_int_phase *= 2;
3020 hdev->disco_int_count = 0;
3021 if (hdev->disco_state == SCAN_LE) {
3022 /* cancel LE scan */
3023 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3024 sizeof(le_cp), &le_cp);
3025 /* start BR scan */
3026 cp.num_rsp = (u8) hdev->disco_int_phase;
3027 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3028 sizeof(cp), &cp);
3029 hdev->disco_state = SCAN_BR;
3030 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003031 }
3032 }
3033
Brian Gix568dde92012-01-11 16:18:04 -08003034done:
3035 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003036 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003037}
Antti Julku5e762442011-08-25 16:48:02 +03003038
Brian Gixa68668b2011-08-11 15:49:36 -07003039
3040int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003041{
Johan Hedberga88a9652011-03-30 13:18:12 +03003042 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003043
Johan Hedberga88a9652011-03-30 13:18:12 +03003044 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003045
Johan Hedberga88a9652011-03-30 13:18:12 +03003046 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003047 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003048 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003049
Johan Hedberga88a9652011-03-30 13:18:12 +03003050 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003051}
3052
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303053int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003054{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303055 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003056
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303057 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003058
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303059 bacpy(&ev.bdaddr, bdaddr);
3060 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003061
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303062 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3063 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003064}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003065
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303066int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3067{
3068 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003069
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303070 memset(&ev, 0, sizeof(ev));
3071
3072 bacpy(&ev.bdaddr, bdaddr);
3073 memcpy(ev.dev_class, dev_class, 3);
3074
3075 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3076}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303077
3078int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3079 u16 sub_ver)
3080{
3081 struct mgmt_ev_remote_version ev;
3082
3083 memset(&ev, 0, sizeof(ev));
3084
3085 bacpy(&ev.bdaddr, bdaddr);
3086 ev.lmp_ver = ver;
3087 ev.manufacturer = mnf;
3088 ev.lmp_subver = sub_ver;
3089
3090 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3091}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003092
3093int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3094{
3095 struct mgmt_ev_remote_features ev;
3096
3097 memset(&ev, 0, sizeof(ev));
3098
3099 bacpy(&ev.bdaddr, bdaddr);
3100 memcpy(ev.features, features, sizeof(ev.features));
3101
3102 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3103 NULL);
3104}