blob: ac8542353a5f9db0abdd281b64a7964d4c77b739 [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];
421
422 BT_DBG("%s", hdev->name);
423
424 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
425 return 0;
426
427 cod[0] = hdev->minor_class;
428 cod[1] = hdev->major_class;
429 cod[2] = get_service_classes(hdev);
430
431 if (memcmp(cod, hdev->dev_class, 3) == 0)
432 return 0;
433
434 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
435}
436
437static int set_limited_discoverable(struct sock *sk, u16 index,
438 unsigned char *data, u16 len)
439{
440 struct mgmt_mode *cp;
441 struct hci_dev *hdev;
442 struct pending_cmd *cmd;
443 struct hci_cp_write_current_iac_lap dcp;
444 int update_cod;
445 int err = 0;
446 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
447 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
448
449 cp = (void *) data;
450
451 BT_DBG("hci%u discoverable: %d", index, cp->val);
452
453 if (!cp || len != sizeof(*cp))
454 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
455 EINVAL);
456
457 hdev = hci_dev_get(index);
458 if (!hdev)
459 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
460 ENODEV);
461
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800462 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700463
464 if (!test_bit(HCI_UP, &hdev->flags)) {
465 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
466 ENETDOWN);
467 goto failed;
468 }
469
470 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
471 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
472 EBUSY);
473 goto failed;
474 }
475
476 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
477 test_bit(HCI_PSCAN, &hdev->flags)) {
478 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
479 EALREADY);
480 goto failed;
481 }
482
483 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
484 len);
485 if (!cmd) {
486 err = -ENOMEM;
487 goto failed;
488 }
489
490 memset(&dcp, 0, sizeof(dcp));
491 dcp.num_current_iac = cp->val ? 2 : 1;
492 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
493 update_cod = 1;
494
495 if (cp->val) {
496 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
497 update_cod = 0;
498 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
499 } else {
500 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
501 update_cod = 0;
502 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
503 }
504
505 if (update_cod)
506 err = update_class(hdev);
507
508 if (err >= 0)
509 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
510 sizeof(dcp), &dcp);
511
512 if (err < 0)
513 mgmt_pending_remove(cmd);
514
515failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800516 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700517 hci_dev_put(hdev);
518
519 return err;
520}
521
Johan Hedberg73f22f62010-12-29 16:00:25 +0200522static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
523 u16 len)
524{
525 struct mgmt_mode *cp;
526 struct hci_dev *hdev;
527 struct pending_cmd *cmd;
528 u8 scan;
529 int err;
530
531 cp = (void *) data;
532
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200533 BT_DBG("request for hci%u", index);
534
Johan Hedberg72a734e2010-12-30 00:38:22 +0200535 if (len != sizeof(*cp))
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200536 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
537
538 hdev = hci_dev_get(index);
539 if (!hdev)
540 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
541
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800542 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200543
544 if (!test_bit(HCI_UP, &hdev->flags)) {
545 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
546 goto failed;
547 }
548
549 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
550 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
551 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200552 goto failed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200553 }
554
555 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
556 test_bit(HCI_PSCAN, &hdev->flags)) {
557 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
558 goto failed;
559 }
560
561 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
562 if (!cmd) {
563 err = -ENOMEM;
564 goto failed;
565 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200566
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200567 scan = SCAN_PAGE;
568
569 if (cp->val)
570 scan |= SCAN_INQUIRY;
571
572 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
573 if (err < 0)
574 mgmt_pending_remove(cmd);
575
576failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800577 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200578 hci_dev_put(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200579
580 return err;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200581}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200582
583static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
584 u16 len)
585{
586 struct mgmt_mode *cp;
587 struct hci_dev *hdev;
588 struct pending_cmd *cmd;
589 u8 scan;
590 int err;
591
592 cp = (void *) data;
593
594 BT_DBG("request for hci%u", index);
595
596 if (len != sizeof(*cp))
597 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
598
599 hdev = hci_dev_get(index);
600 if (!hdev)
601 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
602
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800603 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200604
Johan Hedberg73f22f62010-12-29 16:00:25 +0200605 if (!test_bit(HCI_UP, &hdev->flags)) {
606 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
607 goto failed;
608 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200609
Johan Hedberg73f22f62010-12-29 16:00:25 +0200610 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
611 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
612 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
613 goto failed;
614 }
615
616 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
617 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
618 goto failed;
619 }
620
Johan Hedberg72a734e2010-12-30 00:38:22 +0200621 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200622 if (!cmd) {
623 err = -ENOMEM;
624 goto failed;
625 }
626
627 if (cp->val)
628 scan = SCAN_PAGE;
629 else
630 scan = 0;
631
632 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
633 if (err < 0)
634 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200635
636failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800637 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200638 hci_dev_put(hdev);
639
640 return err;
641}
642
643static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
644 struct sock *skip_sk)
645{
646 struct sk_buff *skb;
647 struct mgmt_hdr *hdr;
648
Brian Gixa68668b2011-08-11 15:49:36 -0700649 BT_DBG("hci%d %d", index, event);
650
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200651 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
652 if (!skb)
653 return -ENOMEM;
654
655 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
656
657 hdr = (void *) skb_put(skb, sizeof(*hdr));
658 hdr->opcode = cpu_to_le16(event);
659 hdr->index = cpu_to_le16(index);
660 hdr->len = cpu_to_le16(data_len);
661
662 if (data)
663 memcpy(skb_put(skb, data_len), data, data_len);
664
665 hci_send_to_sock(NULL, skb, skip_sk);
666 kfree_skb(skb);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200667
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200668 return 0;
669}
670
671static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
672{
673 struct mgmt_mode rp;
674
675 rp.val = val;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200676
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200677 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
678}
679
680static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
681 u16 len)
682{
683 struct mgmt_mode *cp, ev;
684 struct hci_dev *hdev;
685 int err;
686
687 cp = (void *) data;
688
689 BT_DBG("request for hci%u", index);
690
691 if (len != sizeof(*cp))
Johan Hedberg053f0212011-01-26 13:07:10 +0200692 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
693
694 hdev = hci_dev_get(index);
695 if (!hdev)
696 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
697
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800698 hci_dev_lock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200699
700 if (cp->val)
701 set_bit(HCI_PAIRABLE, &hdev->flags);
702 else
703 clear_bit(HCI_PAIRABLE, &hdev->flags);
704
705 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
706 if (err < 0)
707 goto failed;
708
709 ev.val = cp->val;
710
711 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
712
713failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800714 hci_dev_unlock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200715 hci_dev_put(hdev);
716
717 return err;
718}
719
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300720#define EIR_FLAGS 0x01 /* flags */
721#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
722#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
723#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
724#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
725#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
726#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
727#define EIR_NAME_SHORT 0x08 /* shortened local name */
728#define EIR_NAME_COMPLETE 0x09 /* complete local name */
729#define EIR_TX_POWER 0x0A /* transmit power level */
730#define EIR_DEVICE_ID 0x10 /* device ID */
731
732#define PNP_INFO_SVCLASS_ID 0x1200
733
734static u8 bluetooth_base_uuid[] = {
735 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
736 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
737};
738
739static u16 get_uuid16(u8 *uuid128)
740{
741 u32 val;
742 int i;
743
744 for (i = 0; i < 12; i++) {
745 if (bluetooth_base_uuid[i] != uuid128[i])
746 return 0;
747 }
748
749 memcpy(&val, &uuid128[12], 4);
750
751 val = le32_to_cpu(val);
752 if (val > 0xffff)
753 return 0;
754
755 return (u16) val;
756}
757
758static void create_eir(struct hci_dev *hdev, u8 *data)
759{
760 u8 *ptr = data;
761 u16 eir_len = 0;
762 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
763 int i, truncated = 0;
764 struct list_head *p;
765 size_t name_len;
766
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530767 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300768
769 if (name_len > 0) {
770 /* EIR Data type */
771 if (name_len > 48) {
772 name_len = 48;
773 ptr[1] = EIR_NAME_SHORT;
774 } else
775 ptr[1] = EIR_NAME_COMPLETE;
776
777 /* EIR Data length */
778 ptr[0] = name_len + 1;
779
780 memcpy(ptr + 2, hdev->dev_name, name_len);
781
782 eir_len += (name_len + 2);
783 ptr += (name_len + 2);
784 }
785
786 memset(uuid16_list, 0, sizeof(uuid16_list));
787
788 /* Group all UUID16 types */
789 list_for_each(p, &hdev->uuids) {
790 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
791 u16 uuid16;
792
793 uuid16 = get_uuid16(uuid->uuid);
794 if (uuid16 == 0)
795 return;
796
797 if (uuid16 < 0x1100)
798 continue;
799
800 if (uuid16 == PNP_INFO_SVCLASS_ID)
801 continue;
802
803 /* Stop if not enough space to put next UUID */
804 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
805 truncated = 1;
806 break;
807 }
808
809 /* Check for duplicates */
810 for (i = 0; uuid16_list[i] != 0; i++)
811 if (uuid16_list[i] == uuid16)
812 break;
813
814 if (uuid16_list[i] == 0) {
815 uuid16_list[i] = uuid16;
816 eir_len += sizeof(u16);
817 }
818 }
819
820 if (uuid16_list[0] != 0) {
821 u8 *length = ptr;
822
823 /* EIR Data type */
824 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
825
826 ptr += 2;
827 eir_len += 2;
828
829 for (i = 0; uuid16_list[i] != 0; i++) {
830 *ptr++ = (uuid16_list[i] & 0x00ff);
831 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
832 }
833
834 /* EIR Data length */
835 *length = (i * sizeof(u16)) + 1;
836 }
837}
838
839static int update_eir(struct hci_dev *hdev)
840{
841 struct hci_cp_write_eir cp;
842
843 if (!(hdev->features[6] & LMP_EXT_INQ))
844 return 0;
845
846 if (hdev->ssp_mode == 0)
847 return 0;
848
849 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
850 return 0;
851
852 memset(&cp, 0, sizeof(cp));
853
854 create_eir(hdev, cp.data);
855
856 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
857 return 0;
858
859 memcpy(hdev->eir, cp.data, sizeof(cp.data));
860
861 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
862}
863
Szymon Janc4e51eae2011-02-25 19:05:48 +0100864static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200865{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200866 struct mgmt_cp_add_uuid *cp;
867 struct hci_dev *hdev;
868 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200869 int err;
870
871 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200872
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200873 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200874
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200875 if (len != sizeof(*cp))
876 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
877
878 hdev = hci_dev_get(index);
879 if (!hdev)
880 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
881
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800882 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200883
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200884 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
885 if (!uuid) {
886 err = -ENOMEM;
887 goto failed;
888 }
889
890 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200891 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892
893 list_add(&uuid->list, &hdev->uuids);
894
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530895 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200896
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530897 err = update_class(hdev);
898 if (err < 0)
899 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300900
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530901 err = update_eir(hdev);
902 if (err < 0)
903 goto failed;
904 } else
905 err = 0;
Johan Hedberg90e70452012-02-23 23:09:40 +0200906
Szymon Janc4e51eae2011-02-25 19:05:48 +0100907 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200908
909failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800910 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200911 hci_dev_put(hdev);
912
913 return err;
914}
915
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg24b78d02012-02-23 23:24:30 +0200917{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100919 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200920 struct hci_dev *hdev;
921 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 +0200922 int err, found;
923
924 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200925
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200926 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928 if (len != sizeof(*cp))
929 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
930
931 hdev = hci_dev_get(index);
932 if (!hdev)
933 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
934
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800935 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200936
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200937 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
938 err = hci_uuids_clear(hdev);
939 goto unlock;
940 }
941
942 found = 0;
943
944 list_for_each_safe(p, n, &hdev->uuids) {
945 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
946
947 if (memcmp(match->uuid, cp->uuid, 16) != 0)
948 continue;
949
950 list_del(&match->list);
951 found++;
952 }
953
954 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100955 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200956 goto unlock;
957 }
958
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530959 if (test_bit(HCI_UP, &hdev->flags)) {
960 err = update_class(hdev);
961 if (err < 0)
962 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200963
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530964 err = update_eir(hdev);
965 if (err < 0)
966 goto unlock;
967 } else
968 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300969
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200971
972unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800973 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200974 hci_dev_put(hdev);
975
976 return err;
977}
978
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
980 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200981{
982 struct hci_dev *hdev;
983 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200984 int err;
985
986 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200987
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200990 if (len != sizeof(*cp))
991 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200992
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200993 hdev = hci_dev_get(index);
994 if (!hdev)
995 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
996
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800997 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998
Brian Gix8a7f1642011-10-17 17:39:46 -0700999 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1000 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001001 hdev->minor_class = cp->minor;
1002
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301003 if (test_bit(HCI_UP, &hdev->flags))
1004 err = update_class(hdev);
1005 else
1006 err = 0;
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001007
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001009 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001010
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001011 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001012 hci_dev_put(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001013
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001014 return err;
1015}
1016
Johan Hedberg03811012010-12-08 00:21:06 +02001017static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1018 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001019{
Johan Hedberg03811012010-12-08 00:21:06 +02001020 struct hci_dev *hdev;
1021 struct mgmt_cp_set_service_cache *cp;
1022 int err;
1023
1024 cp = (void *) data;
1025
1026 if (len != sizeof(*cp))
1027 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
1028
1029 hdev = hci_dev_get(index);
1030 if (!hdev)
1031 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1032
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001033 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001034
1035 BT_DBG("hci%u enable %d", index, cp->enable);
1036
1037 if (cp->enable) {
1038 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1039 err = 0;
1040 } else {
1041 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301042 if (test_bit(HCI_UP, &hdev->flags)) {
1043 err = update_class(hdev);
1044 if (err == 0)
1045 err = update_eir(hdev);
1046 } else
1047 err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02001048 }
1049
1050 if (err == 0)
1051 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1052 0);
1053
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001054 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001055 hci_dev_put(hdev);
1056
1057 return err;
1058}
1059
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001060static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
1061{
1062 struct hci_dev *hdev;
1063 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001065 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001066
1067 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001068
1069 if (len < sizeof(*cp))
1070 return -EINVAL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001071
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001072 key_count = get_unaligned_le16(&cp->key_count);
1073
1074 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001075 if (expected_len > len) {
1076 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1077 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001078 return -EINVAL;
1079 }
1080
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001082 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001083 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001084
Szymon Janc4e51eae2011-02-25 19:05:48 +01001085 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086 key_count);
1087
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001088 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001089
1090 hci_link_keys_clear(hdev);
1091
1092 set_bit(HCI_LINK_KEYS, &hdev->flags);
1093
1094 if (cp->debug_keys)
1095 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1096 else
1097 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1098
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001099 len -= sizeof(*cp);
1100 i = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001101
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001102 while (i < len) {
1103 struct mgmt_key_info *key = (void *) cp->keys + i;
1104
Brian Gixa68668b2011-08-11 15:49:36 -07001105 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001106
Brian Gixcf956772011-10-20 15:18:51 -07001107 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001108 struct key_master_id *id = (void *) key->data;
1109
1110 if (key->dlen != sizeof(struct key_master_id))
1111 continue;
1112
Brian Gixcf956772011-10-20 15:18:51 -07001113 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1114 key->pin_len, key->auth, id->ediv,
1115 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001116
1117 continue;
1118 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001119
Brian Gixcf956772011-10-20 15:18:51 -07001120 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001121 key->pin_len);
1122 }
1123
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001124 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001125
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001126 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127 hci_dev_put(hdev);
1128
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001129 return err;
1130}
1131
Johan Hedberg03811012010-12-08 00:21:06 +02001132static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001133{
Johan Hedberg03811012010-12-08 00:21:06 +02001134 struct hci_dev *hdev;
1135 struct mgmt_cp_remove_key *cp;
1136 struct hci_conn *conn;
1137 int err;
1138
1139 cp = (void *) data;
1140
1141 if (len != sizeof(*cp))
1142 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1143
1144 hdev = hci_dev_get(index);
1145 if (!hdev)
1146 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
1147
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001148 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001149
1150 err = hci_remove_link_key(hdev, &cp->bdaddr);
1151 if (err < 0) {
1152 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
1153 goto unlock;
1154 }
1155
1156 err = 0;
1157
1158 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1159 goto unlock;
1160
1161 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1162 if (conn) {
1163 struct hci_cp_disconnect dc;
1164
1165 put_unaligned_le16(conn->handle, &dc.handle);
1166 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02001168 }
1169
1170unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001171 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001172 hci_dev_put(hdev);
1173
1174 return err;
1175}
1176
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
1178{
1179 struct hci_dev *hdev;
1180 struct mgmt_cp_disconnect *cp;
1181 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001182 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001183 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001184 int err;
1185
1186 BT_DBG("");
1187
1188 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001190 if (len != sizeof(*cp))
1191 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1192
Szymon Janc4e51eae2011-02-25 19:05:48 +01001193 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001197 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001198
1199 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001200 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001201 goto failed;
1202 }
1203
Szymon Janc4e51eae2011-02-25 19:05:48 +01001204 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1205 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001206 goto failed;
1207 }
1208
1209 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1210 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001211 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1212 if (!conn) {
1213 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1214 ENOTCONN);
1215 goto failed;
1216 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001217 }
1218
Szymon Janc4e51eae2011-02-25 19:05:48 +01001219 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001220 if (!cmd) {
1221 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001222 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001223 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001224
1225 put_unaligned_le16(conn->handle, &dc.handle);
1226 dc.reason = 0x13; /* Remote User Terminated Connection */
1227
1228 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1229 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001230 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001231
1232failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001233 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001234 hci_dev_put(hdev);
1235
1236 return err;
1237}
1238
Szymon Janc8ce62842011-03-01 16:55:32 +01001239static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001240{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001241 struct mgmt_rp_get_connections *rp;
1242 struct hci_dev *hdev;
1243 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001244 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246 int i, err;
1247
1248 BT_DBG("");
1249
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001251 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001254 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255
1256 count = 0;
1257 list_for_each(p, &hdev->conn_hash.list) {
1258 count++;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001259 }
1260
Johan Hedberga38528f2011-01-22 06:46:43 +02001261 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1262 rp = kmalloc(rp_len, GFP_ATOMIC);
1263 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264 err = -ENOMEM;
1265 goto unlock;
1266 }
1267
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268 put_unaligned_le16(count, &rp->conn_count);
1269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 read_lock(&hci_dev_list_lock);
1271
Johan Hedberg2784eb42011-01-21 13:56:35 +02001272 i = 0;
1273 list_for_each(p, &hdev->conn_hash.list) {
1274 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1275
1276 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001277 }
1278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 read_unlock(&hci_dev_list_lock);
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001280
Szymon Janc4e51eae2011-02-25 19:05:48 +01001281 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001282
1283unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001284 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001285 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001286 hci_dev_put(hdev);
1287 return err;
1288}
1289
Szymon Janc4e51eae2011-02-25 19:05:48 +01001290static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1291 u16 len)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001292{
Johan Hedberg980e1a52011-01-22 06:10:07 +02001293 struct hci_dev *hdev;
1294 struct mgmt_cp_pin_code_reply *cp;
1295 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001296 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297 int err;
1298
1299 BT_DBG("");
1300
1301 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302
Johan Hedberg980e1a52011-01-22 06:10:07 +02001303 if (len != sizeof(*cp))
1304 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1305
1306 hdev = hci_dev_get(index);
1307 if (!hdev)
1308 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
1309
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001310 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001311
1312 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001313 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314 goto failed;
1315 }
1316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001318 if (!cmd) {
1319 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001321 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001322
1323 bacpy(&reply.bdaddr, &cp->bdaddr);
1324 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001326
1327 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1328 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001329 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001330
1331failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001332 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001333 hci_dev_put(hdev);
1334
1335 return err;
1336}
1337
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301338static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1339 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301341 struct hci_dev *hdev;
1342 struct mgmt_cp_encrypt_link *cp;
1343 struct hci_cp_set_conn_encrypt enc;
1344 struct hci_conn *conn;
1345 int err = 0;
1346
1347 BT_DBG("");
1348
1349 cp = (void *) data;
1350
1351 if (len != sizeof(*cp))
1352 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1353
1354 hdev = hci_dev_get(index);
1355 if (!hdev)
1356 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1357
Brian Gix384ec672012-03-08 18:41:15 -08001358 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301359
1360 if (!test_bit(HCI_UP, &hdev->flags)) {
1361 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001362 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301363 }
1364
Brian Gix384ec672012-03-08 18:41:15 -08001365 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1366 if (!conn) {
1367 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1368 goto done;
1369 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301370
Brian Gix384ec672012-03-08 18:41:15 -08001371 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1372 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1373 goto done;
1374 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301375
1376 if (conn->link_mode & HCI_LM_AUTH) {
1377 enc.handle = cpu_to_le16(conn->handle);
1378 enc.encrypt = cp->enable;
1379 err = hci_send_cmd(hdev,
1380 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1381 } else {
1382 conn->auth_initiator = 1;
1383 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1384 struct hci_cp_auth_requested cp;
1385 cp.handle = cpu_to_le16(conn->handle);
1386 err = hci_send_cmd(conn->hdev,
1387 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1388 }
1389 }
1390
Brian Gix384ec672012-03-08 18:41:15 -08001391done:
1392 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301393 hci_dev_put(hdev);
1394
1395 return err;
1396}
1397
1398
Johan Hedberg980e1a52011-01-22 06:10:07 +02001399static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1400 u16 len)
1401{
1402 struct hci_dev *hdev;
1403 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001405 int err;
1406
1407 BT_DBG("");
1408
1409 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001410
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411 if (len != sizeof(*cp))
1412 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1413 EINVAL);
1414
1415 hdev = hci_dev_get(index);
1416 if (!hdev)
1417 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1418 ENODEV);
1419
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001420 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001421
1422 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001423 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1424 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001425 goto failed;
1426 }
1427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1429 data, len);
1430 if (!cmd) {
1431 err = -ENOMEM;
1432 goto failed;
1433 }
1434
1435 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1436 &cp->bdaddr);
1437 if (err < 0)
1438 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001439
1440failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001441 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001442 hci_dev_put(hdev);
1443
1444 return err;
1445}
1446
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1448 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001449{
1450 struct hci_dev *hdev;
1451 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001452
1453 BT_DBG("");
1454
1455 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001456
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001457 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001458 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001459
Szymon Janc4e51eae2011-02-25 19:05:48 +01001460 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001461 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001462 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001463
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001464 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001465
1466 hdev->io_capability = cp->io_capability;
1467
1468 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001469 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001470
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001471 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001472 hci_dev_put(hdev);
1473
Szymon Janc4e51eae2011-02-25 19:05:48 +01001474 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001475}
1476
Johan Hedberge9a416b2011-02-19 12:05:56 -03001477static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1478{
1479 struct hci_dev *hdev = conn->hdev;
1480 struct list_head *p;
1481
1482 list_for_each(p, &cmd_list) {
1483 struct pending_cmd *cmd;
1484
1485 cmd = list_entry(p, struct pending_cmd, list);
1486
1487 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1488 continue;
1489
1490 if (cmd->index != hdev->id)
1491 continue;
1492
1493 if (cmd->user_data != conn)
1494 continue;
1495
1496 return cmd;
1497 }
1498
1499 return NULL;
1500}
1501
1502static void pairing_complete(struct pending_cmd *cmd, u8 status)
1503{
1504 struct mgmt_rp_pair_device rp;
1505 struct hci_conn *conn = cmd->user_data;
1506
Brian Gixa68668b2011-08-11 15:49:36 -07001507 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508
Johan Hedberge9a416b2011-02-19 12:05:56 -03001509 bacpy(&rp.bdaddr, &conn->dst);
1510 rp.status = status;
1511
Szymon Janc4e51eae2011-02-25 19:05:48 +01001512 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001513
1514 /* So we don't get further callbacks for this connection */
1515 conn->connect_cfm_cb = NULL;
1516 conn->security_cfm_cb = NULL;
1517 conn->disconn_cfm_cb = NULL;
1518
Johan Hedberga664b5b2011-02-19 12:06:02 -03001519 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001520}
1521
1522static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1523{
1524 struct pending_cmd *cmd;
1525
Brian Gixa68668b2011-08-11 15:49:36 -07001526 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001527
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001528 cmd = find_pairing(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001529 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001530 BT_DBG("Unable to find a pending command");
Johan Hedberge9a416b2011-02-19 12:05:56 -03001531 return;
1532 }
1533
1534 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001535 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001536}
1537
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001538static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001539{
Johan Hedberge9a416b2011-02-19 12:05:56 -03001540 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001541
1542 BT_DBG(" %u", status);
1543
1544 cmd = find_pairing(conn);
1545 if (!cmd) {
1546 BT_DBG("Unable to find a pending command");
1547 return;
1548 }
1549
1550 if (conn->type == LE_LINK)
1551 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1552 status ? 0 : 1);
1553 else
1554 pairing_complete(cmd, status);
1555}
1556
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001557static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001558{
1559 struct pending_cmd *cmd;
1560
1561 BT_DBG("conn: %p %u", conn, status);
1562
1563 cmd = find_pairing(conn);
1564 if (!cmd) {
1565 BT_DBG("Unable to find a pending command");
1566 return;
1567 }
Brian Gix114f3a62011-09-27 14:02:20 -07001568
1569 if (status)
1570 pairing_complete(cmd, status);
1571
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001572 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001573}
1574
1575static void discovery_terminated(struct pending_cmd *cmd, void *data)
1576{
Brian Gix6e349d02011-11-28 14:51:14 -08001577 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001578 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001579
1580 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001581 hdev = hci_dev_get(cmd->index);
1582 if (!hdev)
1583 goto not_found;
1584
Brian Gix568dde92012-01-11 16:18:04 -08001585 del_timer(&hdev->disco_le_timer);
1586 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001587 hci_dev_put(hdev);
1588
1589not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001590 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1591
1592 list_del(&cmd->list);
1593
1594 mgmt_pending_free(cmd);
1595}
1596
Johan Hedberge9a416b2011-02-19 12:05:56 -03001597static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
1598{
1599 struct hci_dev *hdev;
1600 struct mgmt_cp_pair_device *cp;
1601 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001602 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001603 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001604 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001605 int err;
1606
1607 BT_DBG("");
1608
Brian Gix64bd5302011-09-08 11:35:48 -07001609 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001610
Brian Gix64bd5302011-09-08 11:35:48 -07001611 if (len != sizeof(*cp))
1612 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1613
Johan Hedberge9a416b2011-02-19 12:05:56 -03001614 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001615
Johan Hedberge9a416b2011-02-19 12:05:56 -03001616 if (!hdev)
1617 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
1618
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001619 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001620
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301621 io_cap = cp->io_cap;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001622
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001623 sec_level = BT_SECURITY_MEDIUM;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301624 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001625
Brian Gixfdd38922011-09-28 16:23:48 -07001626 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1627 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001628 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1629 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001630 } else {
1631 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1632 if (io_cap == 0x04)
1633 io_cap = 0x01;
1634 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1635 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301636 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001637 }
Johan Hedberg1425acb2011-11-11 00:07:35 +02001638
Ville Tervo30e76272011-02-22 16:10:53 -03001639 if (IS_ERR(conn)) {
1640 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001641 goto unlock;
1642 }
1643
1644 if (conn->connect_cfm_cb) {
1645 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001646 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001647 goto unlock;
1648 }
1649
Szymon Janc4e51eae2011-02-25 19:05:48 +01001650 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001651 if (!cmd) {
1652 err = -ENOMEM;
1653 hci_conn_put(conn);
1654 goto unlock;
1655 }
1656
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001657 conn->connect_cfm_cb = pairing_connect_complete_cb;
1658 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001659 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001660 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001661 cmd->user_data = conn;
1662
1663 if (conn->state == BT_CONNECTED &&
1664 hci_conn_security(conn, sec_level, auth_type))
1665 pairing_complete(cmd, 0);
1666
1667 err = 0;
1668
1669unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001670 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001671 hci_dev_put(hdev);
1672
1673 return err;
1674}
1675
Szymon Janc4e51eae2011-02-25 19:05:48 +01001676static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001677 u16 len, u16 opcode)
Johan Hedberg28424702012-02-02 04:02:29 +02001678{
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001680 u16 mgmt_op = opcode, hci_op;
Johan Hedberg28424702012-02-02 04:02:29 +02001681 struct pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03001682 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001683 struct hci_conn *le_conn;
Johan Hedberg28424702012-02-02 04:02:29 +02001684 int err;
1685
Brian Gixa68668b2011-08-11 15:49:36 -07001686 BT_DBG("%d", mgmt_op);
Johan Hedberg28424702012-02-02 04:02:29 +02001687
Brian Gixa68668b2011-08-11 15:49:36 -07001688 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001689 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Johan Hedberg272d90d2012-02-09 15:26:12 +02001690 else
Brian Gixa68668b2011-08-11 15:49:36 -07001691 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Brian Gix47c15e22011-11-16 13:53:14 -08001692
Brian Gixa68668b2011-08-11 15:49:36 -07001693 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001694 return cmd_status(sk, index, mgmt_op, EINVAL);
1695
Szymon Janc4e51eae2011-02-25 19:05:48 +01001696 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001697 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001698 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001699
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001700 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001701
Johan Hedberga5c29682011-02-19 12:05:57 -03001702 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001703 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberg272d90d2012-02-09 15:26:12 +02001704 goto done;
1705 }
1706
Brian Gixa68668b2011-08-11 15:49:36 -07001707 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1708 if (le_conn) {
1709 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
Brian Gix47c15e22011-11-16 13:53:14 -08001710 goto done;
1711 }
Brian Gixa68668b2011-08-11 15:49:36 -07001712 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1713 "Reject" : "Accept");
Brian Gix47c15e22011-11-16 13:53:14 -08001714
Szymon Janc4e51eae2011-02-25 19:05:48 +01001715 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001716 if (!cmd) {
1717 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001718 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001719 }
1720
Brian Gixa68668b2011-08-11 15:49:36 -07001721 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001722 if (err < 0)
1723 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001724
Brian Gix0df4c182011-11-16 13:53:13 -08001725done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001726 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001727 hci_dev_put(hdev);
1728
Johan Hedberga5c29682011-02-19 12:05:57 -03001729 return err;
1730}
1731
Brian Gixa68668b2011-08-11 15:49:36 -07001732static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1733 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08001734{
Brian Gixa68668b2011-08-11 15:49:36 -07001735 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1736 struct hci_cp_remote_name_req hci_cp;
1737 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001738 struct pending_cmd *cmd;
1739 int err;
1740
1741 BT_DBG("");
1742
Brian Gixa68668b2011-08-11 15:49:36 -07001743 if (len != sizeof(*mgmt_cp))
1744 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001745
Brian Gixa68668b2011-08-11 15:49:36 -07001746 hdev = hci_dev_get(index);
1747 if (!hdev)
1748 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001749
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001750 hci_dev_lock_bh(hdev);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001751
Brian Gixa68668b2011-08-11 15:49:36 -07001752 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001753 if (!cmd) {
1754 err = -ENOMEM;
1755 goto failed;
1756 }
1757
Brian Gixa68668b2011-08-11 15:49:36 -07001758 memset(&hci_cp, 0, sizeof(hci_cp));
1759 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1760 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1761 &hci_cp);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001762 if (err < 0)
1763 mgmt_pending_remove(cmd);
1764
1765failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001766 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001767 hci_dev_put(hdev);
1768
Johan Hedbergb312b1612011-03-16 14:29:37 +02001769 return err;
1770}
1771
Brian Gix7f7e16c2011-11-01 16:27:25 -07001772static int set_connection_params(struct sock *sk, u16 index,
1773 unsigned char *data, u16 len)
Szymon Jancc35938b2011-03-22 13:12:21 +01001774{
Brian Gix7f7e16c2011-11-01 16:27:25 -07001775 struct mgmt_cp_set_connection_params *cp = (void *) data;
1776 struct hci_dev *hdev;
1777 struct hci_conn *conn;
1778 int err;
1779
1780 BT_DBG("");
1781
1782 if (len != sizeof(*cp))
1783 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1784 EINVAL);
1785
1786 hdev = hci_dev_get(index);
1787 if (!hdev)
1788 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1789 ENODEV);
1790
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001791 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001792
1793 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1794 if (!conn) {
1795 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1796 ENOTCONN);
1797 goto failed;
1798 }
1799
1800 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1801 le16_to_cpu(cp->interval_max),
1802 le16_to_cpu(cp->slave_latency),
1803 le16_to_cpu(cp->timeout_multiplier));
1804
1805 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1806
1807failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001808 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001809 hci_dev_put(hdev);
1810
1811 return err;
1812}
1813
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001814static int set_rssi_reporter(struct sock *sk, u16 index,
1815 unsigned char *data, u16 len)
1816{
1817 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
1818 struct hci_dev *hdev;
1819 struct hci_conn *conn;
1820 int err = 0;
1821
1822 if (len != sizeof(*cp))
1823 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1824 EINVAL);
1825
1826 hdev = hci_dev_get(index);
1827 if (!hdev)
1828 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1829 ENODEV);
1830
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001831 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001832
1833 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1834
1835 if (!conn) {
1836 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1837 ENOTCONN);
1838 goto failed;
1839 }
1840
1841 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
1842 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
1843 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
1844
1845failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001846 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001847 hci_dev_put(hdev);
1848
1849 return err;
1850}
1851
1852static int unset_rssi_reporter(struct sock *sk, u16 index,
1853 unsigned char *data, u16 len)
1854{
1855 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
1856 struct hci_dev *hdev;
1857 struct hci_conn *conn;
1858 int err = 0;
1859
1860 if (len != sizeof(*cp))
1861 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1862 EINVAL);
1863
1864 hdev = hci_dev_get(index);
1865
1866 if (!hdev)
1867 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1868 ENODEV);
1869
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001870 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001871
1872 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1873
1874 if (!conn) {
1875 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1876 ENOTCONN);
1877 goto failed;
1878 }
1879
1880 hci_conn_unset_rssi_reporter(conn);
1881
1882failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001883 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001884 hci_dev_put(hdev);
1885
1886 return err;
1887}
1888
Johan Hedberg03811012010-12-08 00:21:06 +02001889static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1890 u16 len)
1891{
1892 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1893 struct hci_cp_write_local_name hci_cp;
1894 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01001895 struct pending_cmd *cmd;
1896 int err;
1897
Johan Hedberg03811012010-12-08 00:21:06 +02001898 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01001899
Johan Hedberg03811012010-12-08 00:21:06 +02001900 if (len != sizeof(*mgmt_cp))
1901 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01001902
Johan Hedberg03811012010-12-08 00:21:06 +02001903 hdev = hci_dev_get(index);
1904 if (!hdev)
1905 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1906
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001907 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001908
1909 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1910 if (!cmd) {
1911 err = -ENOMEM;
1912 goto failed;
1913 }
1914
1915 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1916 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1917 &hci_cp);
1918 if (err < 0)
1919 mgmt_pending_remove(cmd);
1920
1921failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001922 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001923 hci_dev_put(hdev);
1924
1925 return err;
1926}
1927
Brian Gixa68668b2011-08-11 15:49:36 -07001928static void discovery_rsp(struct pending_cmd *cmd, void *data)
1929{
1930 struct mgmt_mode ev;
1931
1932 BT_DBG("");
1933 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1934 ev.val = 1;
1935 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1936 } else {
1937 ev.val = 0;
1938 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1939 NULL, 0);
1940 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001941 struct hci_dev *hdev = hci_dev_get(cmd->index);
1942 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08001943 del_timer(&hdev->disco_le_timer);
1944 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001945 hci_dev_put(hdev);
1946 }
Brian Gixa68668b2011-08-11 15:49:36 -07001947 }
1948 }
1949
1950 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1951
1952 list_del(&cmd->list);
1953
1954 mgmt_pending_free(cmd);
1955}
1956
1957void mgmt_inquiry_started(u16 index)
1958{
1959 BT_DBG("");
1960 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1961 discovery_rsp, NULL);
1962}
1963
1964void mgmt_inquiry_complete_evt(u16 index, u8 status)
1965{
1966 struct hci_dev *hdev;
1967 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08001968 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001969 int err = -1;
1970
1971 BT_DBG("");
1972
1973 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001974
Brian Gixa68668b2011-08-11 15:49:36 -07001975 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07001976
1977 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1978 discovery_terminated, NULL);
1979
1980 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001981
Brian Gix64bd5302011-09-08 11:35:48 -07001982 if (hdev)
1983 goto done;
1984 else
1985 return;
1986 }
Brian Gixa68668b2011-08-11 15:49:36 -07001987
Brian Gix568dde92012-01-11 16:18:04 -08001988 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07001989 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1990 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08001991 if (err >= 0) {
1992 mod_timer(&hdev->disco_le_timer, jiffies +
1993 msecs_to_jiffies(hdev->disco_int_phase * 1000));
1994 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07001995 } else
Brian Gix568dde92012-01-11 16:18:04 -08001996 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07001997 }
1998
Brian Gix568dde92012-01-11 16:18:04 -08001999 if (hdev->disco_state == SCAN_IDLE)
2000 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2001
Brian Gixa68668b2011-08-11 15:49:36 -07002002 if (err < 0)
2003 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2004 discovery_terminated, NULL);
2005
Brian Gix64bd5302011-09-08 11:35:48 -07002006done:
Brian Gixa68668b2011-08-11 15:49:36 -07002007 hci_dev_put(hdev);
2008}
2009
Brian Gix568dde92012-01-11 16:18:04 -08002010void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002011{
Brian Gix568dde92012-01-11 16:18:04 -08002012 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002013 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002014 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002015
Brian Gix568dde92012-01-11 16:18:04 -08002016 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002017
Brian Gix568dde92012-01-11 16:18:04 -08002018 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002019
Brian Gix568dde92012-01-11 16:18:04 -08002020 if (!hdev)
2021 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002022
Brian Gix568dde92012-01-11 16:18:04 -08002023 hci_dev_lock_bh(hdev);
2024 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002025
Brian Gix568dde92012-01-11 16:18:04 -08002026 if (hdev->disco_state != SCAN_IDLE) {
2027 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002028
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302029 if (test_bit(HCI_UP, &hdev->flags)) {
2030 if (hdev->disco_state == SCAN_LE)
2031 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002032 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302033 else
2034 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2035 NULL);
2036 }
Brian Gix568dde92012-01-11 16:18:04 -08002037 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002038 }
Brian Gix568dde92012-01-11 16:18:04 -08002039
2040 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2041
2042 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2043 if (cmd)
2044 mgmt_pending_remove(cmd);
2045
2046 hci_dev_unlock_bh(hdev);
2047 hci_dev_put(hdev);
2048}
2049
2050void mgmt_disco_le_timeout(unsigned long data)
2051{
2052 struct hci_dev *hdev = (void *)data;
2053 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2054
2055 BT_DBG("hci%d", hdev->id);
2056
2057 hdev = hci_dev_get(hdev->id);
2058
2059 if (!hdev)
2060 return;
2061
2062 hci_dev_lock_bh(hdev);
2063
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302064 if (test_bit(HCI_UP, &hdev->flags)) {
2065 if (hdev->disco_state == SCAN_LE)
2066 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2067 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002068
2069 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302070 if (hdev->disco_state != SCAN_IDLE) {
2071 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2072 hdev->disco_int_phase *= 2;
2073 hdev->disco_int_count = 0;
2074 cp.num_rsp = (u8) hdev->disco_int_phase;
2075 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2076 hdev->disco_state = SCAN_BR;
2077 }
Brian Gix568dde92012-01-11 16:18:04 -08002078 }
2079
2080 hci_dev_unlock_bh(hdev);
2081 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002082}
2083
2084static int start_discovery(struct sock *sk, u16 index)
2085{
2086 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2087 struct hci_dev *hdev;
2088 struct pending_cmd *cmd;
2089 int err;
2090
2091 BT_DBG("");
2092
2093 hdev = hci_dev_get(index);
2094 if (!hdev)
2095 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2096
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002097 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002098
Brian Gix568dde92012-01-11 16:18:04 -08002099 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2100 err = -EBUSY;
2101 goto failed;
2102 }
2103
Brian Gixa68668b2011-08-11 15:49:36 -07002104 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2105 if (!cmd) {
2106 err = -ENOMEM;
2107 goto failed;
2108 }
2109
2110 /* If LE Capable, we will alternate between BR/EDR and LE */
2111 if (lmp_le_capable(hdev)) {
2112 struct hci_cp_le_set_scan_parameters le_cp;
2113
2114 /* Shorten BR scan params */
2115 cp.num_rsp = 1;
2116 cp.length /= 2;
2117
2118 /* Setup LE scan params */
2119 memset(&le_cp, 0, sizeof(le_cp));
2120 le_cp.type = 0x01; /* Active scanning */
2121 /* The recommended value for scan interval and window is
2122 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2123 le_cp.interval = cpu_to_le16(0x0012);
2124 le_cp.window = cpu_to_le16(0x0012);
2125 le_cp.own_bdaddr_type = 0; /* Public address */
2126 le_cp.filter = 0; /* Accept all adv packets */
2127
2128 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2129 sizeof(le_cp), &le_cp);
2130 }
2131
2132 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2133
2134 if (err < 0)
2135 mgmt_pending_remove(cmd);
2136 else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002137 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2138 if (!cmd)
2139 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2140 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002141 hdev->disco_int_phase = 1;
2142 hdev->disco_int_count = 0;
2143 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002144 del_timer(&hdev->disco_le_timer);
2145 del_timer(&hdev->disco_timer);
2146 mod_timer(&hdev->disco_timer,
2147 jiffies + msecs_to_jiffies(20000));
Brian Gixa68668b2011-08-11 15:49:36 -07002148 }
2149
2150failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002151 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002152 hci_dev_put(hdev);
2153
Brian Gix568dde92012-01-11 16:18:04 -08002154 if (err < 0)
2155 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2156
Brian Gixa68668b2011-08-11 15:49:36 -07002157 return err;
2158}
2159
2160static int stop_discovery(struct sock *sk, u16 index)
2161{
2162 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2163 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002164 struct hci_dev *hdev;
2165 struct pending_cmd *cmd = NULL;
2166 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002167 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002168
2169 BT_DBG("");
2170
2171 hdev = hci_dev_get(index);
2172 if (!hdev)
2173 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2174
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002175 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002176
Brian Gix568dde92012-01-11 16:18:04 -08002177 state = hdev->disco_state;
2178 hdev->disco_state = SCAN_IDLE;
2179 del_timer(&hdev->disco_le_timer);
2180 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002181
Brian Gix568dde92012-01-11 16:18:04 -08002182 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002183 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2184 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002185 if (err >= 0) {
2186 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2187 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002188
Brian Gix568dde92012-01-11 16:18:04 -08002189 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2190 NULL, 0);
2191 }
Brian Gixa68668b2011-08-11 15:49:36 -07002192 }
2193
Brian Gix568dde92012-01-11 16:18:04 -08002194 if (err < 0)
2195 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002196
Brian Gix568dde92012-01-11 16:18:04 -08002197 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002198 if (err < 0 && cmd)
2199 mgmt_pending_remove(cmd);
2200
2201 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2202
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002203 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002204 hci_dev_put(hdev);
2205
2206 if (err < 0)
2207 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2208 else
2209 return err;
2210}
2211
Szymon Jancc35938b2011-03-22 13:12:21 +01002212static int read_local_oob_data(struct sock *sk, u16 index)
2213{
2214 struct hci_dev *hdev;
2215 struct pending_cmd *cmd;
2216 int err;
2217
2218 BT_DBG("hci%u", index);
2219
2220 hdev = hci_dev_get(index);
2221 if (!hdev)
2222 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2223 ENODEV);
2224
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002225 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002226
2227 if (!test_bit(HCI_UP, &hdev->flags)) {
2228 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2229 ENETDOWN);
2230 goto unlock;
2231 }
2232
2233 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2234 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2235 EOPNOTSUPP);
2236 goto unlock;
2237 }
2238
2239 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2240 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2241 goto unlock;
2242 }
2243
2244 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2245 if (!cmd) {
2246 err = -ENOMEM;
2247 goto unlock;
2248 }
2249
2250 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2251 if (err < 0)
2252 mgmt_pending_remove(cmd);
2253
2254unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002255 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002256 hci_dev_put(hdev);
2257
2258 return err;
2259}
2260
Szymon Janc2763eda2011-03-22 13:12:22 +01002261static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2262 u16 len)
2263{
2264 struct hci_dev *hdev;
2265 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2266 int err;
2267
2268 BT_DBG("hci%u ", index);
2269
2270 if (len != sizeof(*cp))
2271 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2272 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273
Szymon Janc2763eda2011-03-22 13:12:22 +01002274 hdev = hci_dev_get(index);
2275 if (!hdev)
2276 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2277 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002278
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002279 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
2281 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2282 cp->randomizer);
2283 if (err < 0)
2284 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2285 else
2286 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2287 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002288
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002289 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002290 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002291
Szymon Janc2763eda2011-03-22 13:12:22 +01002292 return err;
2293}
2294
2295static int remove_remote_oob_data(struct sock *sk, u16 index,
2296 unsigned char *data, u16 len)
2297{
2298 struct hci_dev *hdev;
2299 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2300 int err;
2301
2302 BT_DBG("hci%u ", index);
2303
2304 if (len != sizeof(*cp))
2305 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2306 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002307
Szymon Janc2763eda2011-03-22 13:12:22 +01002308 hdev = hci_dev_get(index);
2309 if (!hdev)
2310 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2311 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002312
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002313 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002314
2315 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2316 if (err < 0)
2317 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2318 -err);
2319 else
2320 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2321 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002322
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002323 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002324 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002325
2326 return err;
2327}
2328
Johan Hedberg03811012010-12-08 00:21:06 +02002329int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2330{
2331 unsigned char *buf;
2332 struct mgmt_hdr *hdr;
2333 u16 opcode, index, len;
2334 int err;
2335
2336 BT_DBG("got %zu bytes", msglen);
2337
2338 if (msglen < sizeof(*hdr))
2339 return -EINVAL;
2340
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002341 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002342 if (!buf)
2343 return -ENOMEM;
2344
2345 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2346 err = -EFAULT;
2347 goto done;
2348 }
2349
2350 hdr = (struct mgmt_hdr *) buf;
2351 opcode = get_unaligned_le16(&hdr->opcode);
2352 index = get_unaligned_le16(&hdr->index);
2353 len = get_unaligned_le16(&hdr->len);
2354
2355 if (len != msglen - sizeof(*hdr)) {
2356 err = -EINVAL;
2357 goto done;
2358 }
2359
Brian Gixa68668b2011-08-11 15:49:36 -07002360 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002361 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002362 case MGMT_OP_READ_VERSION:
2363 err = read_version(sk);
2364 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002365 case MGMT_OP_READ_INDEX_LIST:
2366 err = read_index_list(sk);
2367 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002368 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002369 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002370 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002371 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002372 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002373 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002374 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002375 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002376 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002377 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2378 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2379 len);
2380 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002381 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002382 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002383 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002384 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002385 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002386 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002387 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002388 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002389 break;
2390 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002391 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002392 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002393 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002394 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002395 break;
2396 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002397 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002398 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002399 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002400 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002401 break;
2402 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002403 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002404 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002406 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002407 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002409 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002410 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002411 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002412 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002413 break;
2414 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002415 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002416 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002417 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002418 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002419 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002420 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002421 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002422 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002424 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002425 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002426 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2427 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002428 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002429 case MGMT_OP_SET_LOCAL_NAME:
2430 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2431 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002432 case MGMT_OP_START_DISCOVERY:
2433 err = start_discovery(sk, index);
2434 break;
2435 case MGMT_OP_STOP_DISCOVERY:
2436 err = stop_discovery(sk, index);
2437 break;
2438 case MGMT_OP_RESOLVE_NAME:
2439 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2440 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002441 case MGMT_OP_SET_CONNECTION_PARAMS:
2442 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2443 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002444 case MGMT_OP_SET_RSSI_REPORTER:
2445 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2446 break;
2447 case MGMT_OP_UNSET_RSSI_REPORTER:
2448 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2449 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002450 case MGMT_OP_READ_LOCAL_OOB_DATA:
2451 err = read_local_oob_data(sk, index);
2452 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002453 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2454 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2455 break;
2456 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2457 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2458 len);
2459 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302460 case MGMT_OP_ENCRYPT_LINK:
2461 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2462 break;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463
Johan Hedberg03811012010-12-08 00:21:06 +02002464 default:
2465 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002466 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002467 break;
2468 }
2469
Johan Hedberge41d8b42010-12-13 21:07:03 +02002470 if (err < 0)
2471 goto done;
2472
Johan Hedberg03811012010-12-08 00:21:06 +02002473 err = msglen;
2474
2475done:
2476 kfree(buf);
2477 return err;
2478}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002479
Johan Hedbergb24752f2011-11-03 14:40:33 +02002480static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2481{
2482 u8 *status = data;
2483
2484 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2485 mgmt_pending_remove(cmd);
2486}
2487
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002488int mgmt_index_added(u16 index)
2489{
Brian Gixa68668b2011-08-11 15:49:36 -07002490 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002491 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002492}
2493
2494int mgmt_index_removed(u16 index)
2495{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002496 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002497
Brian Gixa68668b2011-08-11 15:49:36 -07002498 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002499
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002500 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2501
Szymon Janc4e51eae2011-02-25 19:05:48 +01002502 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002503}
2504
Johan Hedberg73f22f62010-12-29 16:00:25 +02002505struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002506 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002507 struct sock *sk;
2508};
2509
Johan Hedberg72a734e2010-12-30 00:38:22 +02002510static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002511{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002512 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002513 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002514
Johan Hedberg72a734e2010-12-30 00:38:22 +02002515 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002516 return;
2517
Johan Hedberg053f0212011-01-26 13:07:10 +02002518 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002519
2520 list_del(&cmd->list);
2521
2522 if (match->sk == NULL) {
2523 match->sk = cmd->sk;
2524 sock_hold(match->sk);
2525 }
2526
2527 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002528}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002529
2530int mgmt_powered(u16 index, u8 powered)
2531{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002532 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002533 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002534 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002535
Brian Gixa68668b2011-08-11 15:49:36 -07002536 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002537
Johan Hedberg72a734e2010-12-30 00:38:22 +02002538 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002539
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002540 if (!powered) {
2541 u8 status = ENETDOWN;
2542 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002543 }
2544
Johan Hedberg72a734e2010-12-30 00:38:22 +02002545 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002546
Szymon Janc4e51eae2011-02-25 19:05:48 +01002547 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002548
2549 if (match.sk)
2550 sock_put(match.sk);
2551
2552 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002553}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002554
Johan Hedberg73f22f62010-12-29 16:00:25 +02002555int mgmt_discoverable(u16 index, u8 discoverable)
2556{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002557 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002558 struct cmd_lookup match = { discoverable, NULL };
2559 int ret;
2560
Szymon Jancb8534e02011-03-01 16:55:34 +01002561 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002562
Johan Hedberg73f22f62010-12-29 16:00:25 +02002563 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002564
Szymon Janc4e51eae2011-02-25 19:05:48 +01002565 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2566 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002567
Johan Hedberg73f22f62010-12-29 16:00:25 +02002568 if (match.sk)
2569 sock_put(match.sk);
2570
2571 return ret;
2572}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002573
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002574int mgmt_connectable(u16 index, u8 connectable)
2575{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002576 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002577 struct cmd_lookup match = { connectable, NULL };
2578 int ret;
2579
Johan Hedberg72a734e2010-12-30 00:38:22 +02002580 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002581
Johan Hedberg03811012010-12-08 00:21:06 +02002582 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002583
Szymon Janc4e51eae2011-02-25 19:05:48 +01002584 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002585
2586 if (match.sk)
2587 sock_put(match.sk);
2588
2589 return ret;
2590}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002591
Brian Gixa68668b2011-08-11 15:49:36 -07002592int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002593{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002594 struct mgmt_ev_new_key *ev;
2595 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002596
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002597 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2598 ev = kzalloc(total, GFP_ATOMIC);
2599 if (!ev)
2600 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002601
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002602 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002603 ev->key.addr_type = key->addr_type;
2604 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002605 memcpy(ev->key.val, key->val, 16);
2606 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002607 ev->key.auth = key->auth;
2608 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002609 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002610
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002611 memcpy(ev->key.data, key->data, key->dlen);
2612
2613 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2614
2615 kfree(ev);
2616
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002617 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002618}
2619
Brian Gix2e2f50d2011-09-13 12:36:04 -07002620int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002621{
Johan Hedbergf7520542011-01-20 12:34:39 +02002622 struct mgmt_ev_connected ev;
Johan Hedbergca69b792011-11-11 18:10:00 +02002623
Johan Hedbergf7520542011-01-20 12:34:39 +02002624 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002625 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002626
Szymon Janc4e51eae2011-02-25 19:05:48 +01002627 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002628}
2629
Johan Hedberg8962ee72011-01-20 12:40:27 +02002630static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2631{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002632 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002633 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002634 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002635
Johan Hedberga38528f2011-01-22 06:46:43 +02002636 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002637
Szymon Janc4e51eae2011-02-25 19:05:48 +01002638 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002639
2640 *sk = cmd->sk;
2641 sock_hold(*sk);
2642
Johan Hedberga664b5b2011-02-19 12:06:02 -03002643 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002644}
2645
Johan Hedbergf7520542011-01-20 12:34:39 +02002646int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002647{
Johan Hedbergf7520542011-01-20 12:34:39 +02002648 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002649 struct sock *sk = NULL;
2650 int err;
2651
2652 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002653
Johan Hedbergf7520542011-01-20 12:34:39 +02002654 bacpy(&ev.bdaddr, bdaddr);
2655
Szymon Janc4e51eae2011-02-25 19:05:48 +01002656 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002657
2658 if (sk)
2659 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002660
Johan Hedberg8962ee72011-01-20 12:40:27 +02002661 return err;
2662}
2663
2664int mgmt_disconnect_failed(u16 index)
2665{
2666 struct pending_cmd *cmd;
2667 int err;
2668
2669 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2670 if (!cmd)
2671 return -ENOENT;
2672
Szymon Janc4e51eae2011-02-25 19:05:48 +01002673 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002674
Johan Hedberga664b5b2011-02-19 12:06:02 -03002675 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002676
2677 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002678}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002679
2680int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2681{
2682 struct mgmt_ev_connect_failed ev;
2683
Johan Hedberg17d5c042011-01-22 06:09:08 +02002684 bacpy(&ev.bdaddr, bdaddr);
2685 ev.status = status;
2686
Szymon Janc4e51eae2011-02-25 19:05:48 +01002687 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002688}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002691{
2692 struct mgmt_ev_pin_code_request ev;
2693
Brian Gixa68668b2011-08-11 15:49:36 -07002694 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002695
Johan Hedberg980e1a52011-01-22 06:10:07 +02002696 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002697 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002698
Szymon Janc4e51eae2011-02-25 19:05:48 +01002699 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2700 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701}
2702
2703int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2704{
2705 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002706 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002707 int err;
2708
2709 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2710 if (!cmd)
2711 return -ENOENT;
2712
Johan Hedbergac56fb12011-02-19 12:05:59 -03002713 bacpy(&rp.bdaddr, bdaddr);
2714 rp.status = status;
2715
Szymon Janc4e51eae2011-02-25 19:05:48 +01002716 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2717 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
Johan Hedberga664b5b2011-02-19 12:06:02 -03002719 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720
2721 return err;
2722}
2723
2724int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2725{
2726 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002727 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 int err;
2729
2730 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2731 if (!cmd)
2732 return -ENOENT;
2733
Johan Hedbergac56fb12011-02-19 12:05:59 -03002734 bacpy(&rp.bdaddr, bdaddr);
2735 rp.status = status;
2736
Szymon Janc4e51eae2011-02-25 19:05:48 +01002737 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2738 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002739
Johan Hedberga664b5b2011-02-19 12:06:02 -03002740 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002741
2742 return err;
2743}
Johan Hedberga5c29682011-02-19 12:05:57 -03002744
Brian Gixa68668b2011-08-11 15:49:36 -07002745int mgmt_user_confirm_request(u16 index, u8 event,
2746 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002747{
2748 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002749 struct hci_conn *conn = NULL;
2750 struct hci_dev *hdev;
2751 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03002752
Brian Gixa68668b2011-08-11 15:49:36 -07002753 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002754
Brian Gixa68668b2011-08-11 15:49:36 -07002755 hdev = hci_dev_get(index);
2756
Brian Gix64bd5302011-09-08 11:35:48 -07002757 if (!hdev)
2758 return -ENODEV;
2759
Brian Gix64bd5302011-09-08 11:35:48 -07002760 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002761
2762 ev.auto_confirm = 0;
2763
2764 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2765 goto no_auto_confirm;
2766
2767 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2768 rem_cap = conn->remote_cap;
2769 loc_mitm = conn->auth_type & 0x01;
2770 rem_mitm = conn->remote_auth & 0x01;
2771
Brian Gixdbf59292011-11-11 15:45:17 -08002772 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2773 conn->auth_initiator && rem_cap == 0x03)
2774 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302775 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
2776 if (!loc_mitm && !rem_mitm)
2777 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07002778 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302779 }
Brian Gixa68668b2011-08-11 15:49:36 -07002780
2781
2782 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2783 ev.auto_confirm = 1;
2784
2785no_auto_confirm:
2786 bacpy(&ev.bdaddr, bdaddr);
2787 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03002788 put_unaligned_le32(value, &ev.value);
2789
Brian Gix64bd5302011-09-08 11:35:48 -07002790 hci_dev_put(hdev);
2791
Brian Gixa68668b2011-08-11 15:49:36 -07002792 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2793 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002794}
2795
Brian Gixa68668b2011-08-11 15:49:36 -07002796int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08002797{
2798 struct mgmt_ev_user_passkey_request ev;
2799
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08002801
Johan Hedberga5c29682011-02-19 12:05:57 -03002802 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002803
Brian Gixa68668b2011-08-11 15:49:36 -07002804 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03002805 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08002806}
2807
Johan Hedberga5c29682011-02-19 12:05:57 -03002808static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2809 u8 opcode)
2810{
2811 struct pending_cmd *cmd;
2812 struct mgmt_rp_user_confirm_reply rp;
2813 int err;
2814
2815 cmd = mgmt_pending_find(opcode, index);
2816 if (!cmd)
2817 return -ENOENT;
2818
Johan Hedberga5c29682011-02-19 12:05:57 -03002819 bacpy(&rp.bdaddr, bdaddr);
2820 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002821 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002822
Johan Hedberga664b5b2011-02-19 12:06:02 -03002823 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002824
2825 return err;
2826}
2827
2828int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2829{
2830 return confirm_reply_complete(index, bdaddr, status,
2831 MGMT_OP_USER_CONFIRM_REPLY);
2832}
2833
Szymon Jancb8534e02011-03-01 16:55:34 +01002834int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002835{
2836 return confirm_reply_complete(index, bdaddr, status,
2837 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2838}
Johan Hedberg2a611692011-02-19 12:06:00 -03002839
2840int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2841{
2842 struct mgmt_ev_auth_failed ev;
2843
Johan Hedberg2a611692011-02-19 12:06:00 -03002844 bacpy(&ev.bdaddr, bdaddr);
2845 ev.status = status;
2846
Szymon Janc4e51eae2011-02-25 19:05:48 +01002847 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002848}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002849
2850int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2851{
2852 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002853 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002854 struct mgmt_cp_set_local_name ev;
2855 int err;
2856
2857 memset(&ev, 0, sizeof(ev));
2858 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2859
2860 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2861 if (!cmd)
2862 goto send_event;
2863
2864 if (status) {
2865 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2866 goto failed;
2867 }
2868
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002869 hdev = hci_dev_get(index);
2870 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002871 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002872 hci_dev_put(hdev);
2873 }
2874
Johan Hedbergb312b1612011-03-16 14:29:37 +02002875 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2876 sizeof(ev));
2877 if (err < 0)
2878 goto failed;
2879
2880send_event:
2881 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2882 cmd ? cmd->sk : NULL);
2883
2884failed:
2885 if (cmd)
2886 mgmt_pending_remove(cmd);
2887 return err;
2888}
Szymon Jancc35938b2011-03-22 13:12:21 +01002889
2890int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2891 u8 status)
2892{
2893 struct pending_cmd *cmd;
2894 int err;
2895
2896 BT_DBG("hci%u status %u", index, status);
2897
2898 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2899 if (!cmd)
2900 return -ENOENT;
2901
2902 if (status) {
2903 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2904 EIO);
2905 } else {
2906 struct mgmt_rp_read_local_oob_data rp;
2907
2908 memcpy(rp.hash, hash, sizeof(rp.hash));
2909 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2910
2911 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2912 &rp, sizeof(rp));
2913 }
2914
2915 mgmt_pending_remove(cmd);
2916
2917 return err;
2918}
Johan Hedberge17acd42011-03-30 23:57:16 +03002919
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002920void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
2921 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002922{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002923 struct mgmt_ev_rssi_update ev;
2924 struct hci_conn *conn;
2925 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002926
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002927 if (status)
2928 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002929
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002930 hdev = hci_dev_get(index);
2931 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002932
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002933 if (!conn)
2934 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002935
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002936 BT_DBG("rssi_update_thresh_exceed : %d ",
2937 conn->rssi_update_thresh_exceed);
2938 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
2939 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002940
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002941 if (conn->rssi_update_thresh_exceed == 1) {
2942 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002943 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002944 memset(&ev, 0, sizeof(ev));
2945 bacpy(&ev.bdaddr, bdaddr);
2946 ev.rssi = rssi;
2947 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2948 sizeof(ev), NULL);
2949 } else {
2950 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2951 conn->rssi_update_interval,
2952 conn->rssi_update_thresh_exceed);
2953 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002954 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002955 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002956 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002957 memset(&ev, 0, sizeof(ev));
2958 bacpy(&ev.bdaddr, bdaddr);
2959 ev.rssi = rssi;
2960 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2961 sizeof(ev), NULL);
2962 } else {
2963 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2964 conn->rssi_update_interval,
2965 conn->rssi_update_thresh_exceed);
2966 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002967 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02002968}
2969
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002970
Brian Gixa68668b2011-08-11 15:49:36 -07002971int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2972 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002973{
2974 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08002975 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02002976 int err;
2977
Brian Gixa68668b2011-08-11 15:49:36 -07002978 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002979
Johan Hedbergf963e8e2012-02-20 23:30:44 +02002980 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02002981
Johan Hedberge17acd42011-03-30 23:57:16 +03002982 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002983 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002984 ev.type = type;
2985 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002986
Brian Gixa68668b2011-08-11 15:49:36 -07002987 if (dev_class)
2988 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002989
Brian Gixa68668b2011-08-11 15:49:36 -07002990 if (eir && eir_len)
2991 memcpy(ev.eir, eir, eir_len);
2992
2993 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2994
2995 if (err < 0)
2996 return err;
2997
Brian Gix568dde92012-01-11 16:18:04 -08002998 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002999
Brian Gix568dde92012-01-11 16:18:04 -08003000 if (!hdev)
3001 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003002
Brian Gix568dde92012-01-11 16:18:04 -08003003 if (hdev->disco_state == SCAN_IDLE)
3004 goto done;
3005
3006 hdev->disco_int_count++;
3007
3008 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3009 /* Inquiry scan for General Discovery LAP */
3010 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3011 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3012
3013 hdev->disco_int_phase *= 2;
3014 hdev->disco_int_count = 0;
3015 if (hdev->disco_state == SCAN_LE) {
3016 /* cancel LE scan */
3017 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3018 sizeof(le_cp), &le_cp);
3019 /* start BR scan */
3020 cp.num_rsp = (u8) hdev->disco_int_phase;
3021 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3022 sizeof(cp), &cp);
3023 hdev->disco_state = SCAN_BR;
3024 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003025 }
3026 }
3027
Brian Gix568dde92012-01-11 16:18:04 -08003028done:
3029 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003030 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003031}
Antti Julku5e762442011-08-25 16:48:02 +03003032
Brian Gixa68668b2011-08-11 15:49:36 -07003033
3034int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003035{
Johan Hedberga88a9652011-03-30 13:18:12 +03003036 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003037
Johan Hedberga88a9652011-03-30 13:18:12 +03003038 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003039
Johan Hedberga88a9652011-03-30 13:18:12 +03003040 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003041 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003042 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003043
Johan Hedberga88a9652011-03-30 13:18:12 +03003044 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003045}
3046
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303047int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003048{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303049 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003050
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303051 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003052
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303053 bacpy(&ev.bdaddr, bdaddr);
3054 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003055
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303056 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3057 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003058}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003059
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303060int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3061{
3062 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003063
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303064 memset(&ev, 0, sizeof(ev));
3065
3066 bacpy(&ev.bdaddr, bdaddr);
3067 memcpy(ev.dev_class, dev_class, 3);
3068
3069 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3070}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303071
3072int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3073 u16 sub_ver)
3074{
3075 struct mgmt_ev_remote_version ev;
3076
3077 memset(&ev, 0, sizeof(ev));
3078
3079 bacpy(&ev.bdaddr, bdaddr);
3080 ev.lmp_ver = ver;
3081 ev.manufacturer = mnf;
3082 ev.lmp_subver = sub_ver;
3083
3084 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3085}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003086
3087int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3088{
3089 struct mgmt_ev_remote_features ev;
3090
3091 memset(&ev, 0, sizeof(ev));
3092
3093 bacpy(&ev.bdaddr, bdaddr);
3094 memcpy(ev.features, features, sizeof(ev.features));
3095
3096 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3097 NULL);
3098}