blob: 8658b94c6714a14553bb53b9bd360458a7c297f6 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
Anantha Krishnan91b11ff2013-01-27 18:20:20 +05304 Copyright (c) 2011-2013 The Linux Foundation. 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
Sunny Kapdi93bef892012-07-30 14:52:56 -0700232 rp.le_white_list_size = hdev->le_white_list_size;
233
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800234 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200238}
Johan Hedberg03811012010-12-08 00:21:06 +0200239
Mat Martineau8cd0df02011-08-23 16:23:36 -0700240static void mgmt_pending_free_worker(struct work_struct *work)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200241{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700242 struct mgmt_pending_free_work *free_work =
243 container_of(work, struct mgmt_pending_free_work, work);
Johan Hedberg03811012010-12-08 00:21:06 +0200244
Mat Martineau8cd0df02011-08-23 16:23:36 -0700245 BT_DBG("sk %p", free_work->sk);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100246
Mat Martineau8cd0df02011-08-23 16:23:36 -0700247 sock_put(free_work->sk);
248 kfree(free_work);
Johan Hedbergc542a062011-01-26 13:11:03 +0200249}
250
Johan Hedberg03811012010-12-08 00:21:06 +0200251static void mgmt_pending_free(struct pending_cmd *cmd)
252{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700253 struct mgmt_pending_free_work *free_work;
254 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700255
Mat Martineau8cd0df02011-08-23 16:23:36 -0700256 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
257
Johan Hedberg03811012010-12-08 00:21:06 +0200258 kfree(cmd->param);
259 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700260
261 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
262 if (free_work) {
263 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
264 free_work->sk = sk;
265
266 if (!schedule_work(&free_work->work))
267 kfree(free_work);
268 }
Johan Hedberg03811012010-12-08 00:21:06 +0200269}
270
271static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
272 u16 index, void *data, u16 len)
273{
274 struct pending_cmd *cmd;
275
Brian Gixa68668b2011-08-11 15:49:36 -0700276 BT_DBG("%d", opcode);
277
Johan Hedberg03811012010-12-08 00:21:06 +0200278 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
279 if (!cmd)
280 return NULL;
281
282 cmd->opcode = opcode;
283 cmd->index = index;
284
285 cmd->param = kmalloc(len, GFP_ATOMIC);
286 if (!cmd->param) {
287 kfree(cmd);
288 return NULL;
289 }
290
291 if (data)
292 memcpy(cmd->param, data, len);
293
294 cmd->sk = sk;
295 sock_hold(sk);
296
297 list_add(&cmd->list, &cmd_list);
298
299 return cmd;
300}
301
302static void mgmt_pending_foreach(u16 opcode, int index,
303 void (*cb)(struct pending_cmd *cmd, void *data),
304 void *data)
Johan Hedberge41d8b42010-12-13 21:07:03 +0200305{
306 struct list_head *p, *n;
Johan Hedberg03811012010-12-08 00:21:06 +0200307
Brian Gixa68668b2011-08-11 15:49:36 -0700308 BT_DBG(" %d", opcode);
309
Johan Hedberg03811012010-12-08 00:21:06 +0200310 list_for_each_safe(p, n, &cmd_list) {
311 struct pending_cmd *cmd;
312
313 cmd = list_entry(p, struct pending_cmd, list);
314
Johan Hedberg931bc4e2011-11-03 14:40:33 +0200315 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedberg03811012010-12-08 00:21:06 +0200316 continue;
317
318 if (index >= 0 && cmd->index != index)
319 continue;
320
321 cb(cmd, data);
322 }
323}
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324
325static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
326{
327 struct list_head *p;
328
Brian Gixa68668b2011-08-11 15:49:36 -0700329 BT_DBG(" %d", opcode);
330
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331 list_for_each(p, &cmd_list) {
332 struct pending_cmd *cmd;
333
334 cmd = list_entry(p, struct pending_cmd, list);
335
336 if (cmd->opcode != opcode)
337 continue;
338
339 if (index >= 0 && cmd->index != index)
340 continue;
341
342 return cmd;
343 }
344
345 return NULL;
346}
347
348static void mgmt_pending_remove(struct pending_cmd *cmd)
349{
Brian Gixa68668b2011-08-11 15:49:36 -0700350 BT_DBG(" %d", cmd->opcode);
351
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352 list_del(&cmd->list);
353 mgmt_pending_free(cmd);
354}
355
356static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
357{
358 struct mgmt_mode *cp;
359 struct hci_dev *hdev;
360 struct pending_cmd *cmd;
361 int err, up;
362
363 cp = (void *) data;
364
365 BT_DBG("request for hci%u", index);
366
367 if (len != sizeof(*cp))
368 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
369
370 hdev = hci_dev_get(index);
371 if (!hdev)
372 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
373
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800374 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375
376 up = test_bit(HCI_UP, &hdev->flags);
377 if ((cp->val && up) || (!cp->val && !up)) {
378 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
379 goto failed;
380 }
381
382 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
383 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
384 goto failed;
385 }
Bhasker Neti8bfd3c52013-02-25 22:07:43 +0530386 /* Avoid queing power_on/off when the set up is going on via
387 * hci_register_dev
388 */
389 if (!test_bit(HCI_SETUP, &hdev->flags)) {
390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data,
391 len);
392 if (!cmd) {
393 err = -ENOMEM;
394 goto failed;
395 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396
Bhasker Neti8bfd3c52013-02-25 22:07:43 +0530397 hci_dev_unlock_bh(hdev);
398
399 if (cp->val)
400 queue_work(hdev->workqueue, &hdev->power_on);
401 else
402 queue_work(hdev->workqueue, &hdev->power_off);
403
404 err = 0;
405 hci_dev_put(hdev);
406 } else {
407 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200408 goto failed;
409 }
Bhasker Neti86a4b322012-10-29 15:22:33 +0530410 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200411
412failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800413 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200414 hci_dev_put(hdev);
415 return err;
416}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200417
Brian Gix8a7f1642011-10-17 17:39:46 -0700418static u8 get_service_classes(struct hci_dev *hdev)
419{
420 struct list_head *p;
421 u8 val = 0;
422
423 list_for_each(p, &hdev->uuids) {
424 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
425
426 val |= uuid->svc_hint;
427 }
428
429 return val;
430}
431
432static int update_class(struct hci_dev *hdev)
433{
434 u8 cod[3];
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530435 int err = 0;
Brian Gix8a7f1642011-10-17 17:39:46 -0700436
437 BT_DBG("%s", hdev->name);
438
439 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
440 return 0;
441
442 cod[0] = hdev->minor_class;
443 cod[1] = hdev->major_class;
444 cod[2] = get_service_classes(hdev);
445
446 if (memcmp(cod, hdev->dev_class, 3) == 0)
447 return 0;
448
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530449 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
450
451 if (err == 0)
452 memcpy(hdev->dev_class, cod, 3);
453
454 return err;
Brian Gix8a7f1642011-10-17 17:39:46 -0700455}
456
457static int set_limited_discoverable(struct sock *sk, u16 index,
458 unsigned char *data, u16 len)
459{
460 struct mgmt_mode *cp;
461 struct hci_dev *hdev;
462 struct pending_cmd *cmd;
463 struct hci_cp_write_current_iac_lap dcp;
464 int update_cod;
465 int err = 0;
466 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
467 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
468
469 cp = (void *) data;
470
471 BT_DBG("hci%u discoverable: %d", index, cp->val);
472
473 if (!cp || len != sizeof(*cp))
474 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
475 EINVAL);
476
477 hdev = hci_dev_get(index);
478 if (!hdev)
479 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
480 ENODEV);
481
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800482 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700483
484 if (!test_bit(HCI_UP, &hdev->flags)) {
485 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
486 ENETDOWN);
487 goto failed;
488 }
489
490 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
491 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
492 EBUSY);
493 goto failed;
494 }
495
496 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
497 test_bit(HCI_PSCAN, &hdev->flags)) {
498 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
499 EALREADY);
500 goto failed;
501 }
502
503 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
504 len);
505 if (!cmd) {
506 err = -ENOMEM;
507 goto failed;
508 }
509
510 memset(&dcp, 0, sizeof(dcp));
511 dcp.num_current_iac = cp->val ? 2 : 1;
512 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
513 update_cod = 1;
514
515 if (cp->val) {
516 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
517 update_cod = 0;
518 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
519 } else {
520 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
521 update_cod = 0;
522 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
523 }
524
525 if (update_cod)
526 err = update_class(hdev);
527
528 if (err >= 0)
529 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
530 sizeof(dcp), &dcp);
531
532 if (err < 0)
533 mgmt_pending_remove(cmd);
534
535failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800536 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700537 hci_dev_put(hdev);
538
539 return err;
540}
541
Johan Hedberg73f22f62010-12-29 16:00:25 +0200542static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
543 u16 len)
544{
545 struct mgmt_mode *cp;
546 struct hci_dev *hdev;
547 struct pending_cmd *cmd;
548 u8 scan;
549 int err;
550
551 cp = (void *) data;
552
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200553 BT_DBG("request for hci%u", index);
554
Johan Hedberg72a734e2010-12-30 00:38:22 +0200555 if (len != sizeof(*cp))
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200556 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
557
558 hdev = hci_dev_get(index);
559 if (!hdev)
560 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
561
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800562 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200563
564 if (!test_bit(HCI_UP, &hdev->flags)) {
565 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
566 goto failed;
567 }
568
569 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
570 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
571 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200572 goto failed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200573 }
574
575 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
576 test_bit(HCI_PSCAN, &hdev->flags)) {
577 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
578 goto failed;
579 }
580
581 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
582 if (!cmd) {
583 err = -ENOMEM;
584 goto failed;
585 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200586
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200587 scan = SCAN_PAGE;
588
589 if (cp->val)
590 scan |= SCAN_INQUIRY;
591
592 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
593 if (err < 0)
594 mgmt_pending_remove(cmd);
595
596failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800597 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200598 hci_dev_put(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200599
600 return err;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200601}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200602
603static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
604 u16 len)
605{
606 struct mgmt_mode *cp;
607 struct hci_dev *hdev;
608 struct pending_cmd *cmd;
609 u8 scan;
610 int err;
611
612 cp = (void *) data;
613
614 BT_DBG("request for hci%u", index);
615
616 if (len != sizeof(*cp))
617 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
618
619 hdev = hci_dev_get(index);
620 if (!hdev)
621 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
622
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800623 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200624
Johan Hedberg73f22f62010-12-29 16:00:25 +0200625 if (!test_bit(HCI_UP, &hdev->flags)) {
626 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
627 goto failed;
628 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200629
Johan Hedberg73f22f62010-12-29 16:00:25 +0200630 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
631 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
632 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
633 goto failed;
634 }
635
636 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
637 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
638 goto failed;
639 }
640
Johan Hedberg72a734e2010-12-30 00:38:22 +0200641 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200642 if (!cmd) {
643 err = -ENOMEM;
644 goto failed;
645 }
646
647 if (cp->val)
648 scan = SCAN_PAGE;
649 else
650 scan = 0;
651
652 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
653 if (err < 0)
654 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200655
656failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800657 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200658 hci_dev_put(hdev);
659
660 return err;
661}
662
663static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
664 struct sock *skip_sk)
665{
666 struct sk_buff *skb;
667 struct mgmt_hdr *hdr;
668
Brian Gixa68668b2011-08-11 15:49:36 -0700669 BT_DBG("hci%d %d", index, event);
670
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200671 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
672 if (!skb)
673 return -ENOMEM;
674
675 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
676
677 hdr = (void *) skb_put(skb, sizeof(*hdr));
678 hdr->opcode = cpu_to_le16(event);
679 hdr->index = cpu_to_le16(index);
680 hdr->len = cpu_to_le16(data_len);
681
682 if (data)
683 memcpy(skb_put(skb, data_len), data, data_len);
684
685 hci_send_to_sock(NULL, skb, skip_sk);
686 kfree_skb(skb);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200687
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200688 return 0;
689}
690
691static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
692{
693 struct mgmt_mode rp;
694
695 rp.val = val;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200696
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200697 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
698}
699
700static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
701 u16 len)
702{
703 struct mgmt_mode *cp, ev;
704 struct hci_dev *hdev;
705 int err;
706
707 cp = (void *) data;
708
709 BT_DBG("request for hci%u", index);
710
711 if (len != sizeof(*cp))
Johan Hedberg053f0212011-01-26 13:07:10 +0200712 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
713
714 hdev = hci_dev_get(index);
715 if (!hdev)
716 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
717
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800718 hci_dev_lock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200719
720 if (cp->val)
721 set_bit(HCI_PAIRABLE, &hdev->flags);
722 else
723 clear_bit(HCI_PAIRABLE, &hdev->flags);
724
725 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
726 if (err < 0)
727 goto failed;
728
729 ev.val = cp->val;
730
731 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
732
733failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800734 hci_dev_unlock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200735 hci_dev_put(hdev);
736
737 return err;
738}
739
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300740#define EIR_FLAGS 0x01 /* flags */
741#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
742#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
743#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
744#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
745#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
746#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
747#define EIR_NAME_SHORT 0x08 /* shortened local name */
748#define EIR_NAME_COMPLETE 0x09 /* complete local name */
749#define EIR_TX_POWER 0x0A /* transmit power level */
750#define EIR_DEVICE_ID 0x10 /* device ID */
751
752#define PNP_INFO_SVCLASS_ID 0x1200
753
754static u8 bluetooth_base_uuid[] = {
755 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
756 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757};
758
759static u16 get_uuid16(u8 *uuid128)
760{
761 u32 val;
762 int i;
763
764 for (i = 0; i < 12; i++) {
765 if (bluetooth_base_uuid[i] != uuid128[i])
766 return 0;
767 }
768
769 memcpy(&val, &uuid128[12], 4);
770
771 val = le32_to_cpu(val);
772 if (val > 0xffff)
773 return 0;
774
775 return (u16) val;
776}
777
778static void create_eir(struct hci_dev *hdev, u8 *data)
779{
780 u8 *ptr = data;
781 u16 eir_len = 0;
782 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
783 int i, truncated = 0;
784 struct list_head *p;
785 size_t name_len;
786
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530787 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300788
789 if (name_len > 0) {
790 /* EIR Data type */
791 if (name_len > 48) {
792 name_len = 48;
793 ptr[1] = EIR_NAME_SHORT;
794 } else
795 ptr[1] = EIR_NAME_COMPLETE;
796
797 /* EIR Data length */
798 ptr[0] = name_len + 1;
799
800 memcpy(ptr + 2, hdev->dev_name, name_len);
801
802 eir_len += (name_len + 2);
803 ptr += (name_len + 2);
804 }
805
806 memset(uuid16_list, 0, sizeof(uuid16_list));
807
808 /* Group all UUID16 types */
809 list_for_each(p, &hdev->uuids) {
810 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
811 u16 uuid16;
812
813 uuid16 = get_uuid16(uuid->uuid);
814 if (uuid16 == 0)
815 return;
816
817 if (uuid16 < 0x1100)
818 continue;
819
820 if (uuid16 == PNP_INFO_SVCLASS_ID)
821 continue;
822
823 /* Stop if not enough space to put next UUID */
824 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
825 truncated = 1;
826 break;
827 }
828
829 /* Check for duplicates */
830 for (i = 0; uuid16_list[i] != 0; i++)
831 if (uuid16_list[i] == uuid16)
832 break;
833
834 if (uuid16_list[i] == 0) {
835 uuid16_list[i] = uuid16;
836 eir_len += sizeof(u16);
837 }
838 }
839
840 if (uuid16_list[0] != 0) {
841 u8 *length = ptr;
842
843 /* EIR Data type */
844 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
845
846 ptr += 2;
847 eir_len += 2;
848
849 for (i = 0; uuid16_list[i] != 0; i++) {
850 *ptr++ = (uuid16_list[i] & 0x00ff);
851 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
852 }
853
854 /* EIR Data length */
855 *length = (i * sizeof(u16)) + 1;
856 }
857}
858
859static int update_eir(struct hci_dev *hdev)
860{
861 struct hci_cp_write_eir cp;
862
863 if (!(hdev->features[6] & LMP_EXT_INQ))
864 return 0;
865
866 if (hdev->ssp_mode == 0)
867 return 0;
868
869 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
870 return 0;
871
872 memset(&cp, 0, sizeof(cp));
873
874 create_eir(hdev, cp.data);
875
876 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
877 return 0;
878
879 memcpy(hdev->eir, cp.data, sizeof(cp.data));
880
881 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
882}
883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200886 struct mgmt_cp_add_uuid *cp;
887 struct hci_dev *hdev;
888 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889 int err;
890
891 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200893 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200894
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200895 if (len != sizeof(*cp))
896 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
897
898 hdev = hci_dev_get(index);
899 if (!hdev)
900 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
901
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800902 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200903
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200904 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
905 if (!uuid) {
906 err = -ENOMEM;
907 goto failed;
908 }
909
910 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200911 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200912
913 list_add(&uuid->list, &hdev->uuids);
914
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530915 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200916
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530917 err = update_class(hdev);
918 if (err < 0)
919 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300920
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530921 err = update_eir(hdev);
922 if (err < 0)
923 goto failed;
924 } else
925 err = 0;
Johan Hedberg90e70452012-02-23 23:09:40 +0200926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928
929failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800930 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200931 hci_dev_put(hdev);
932
933 return err;
934}
935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg24b78d02012-02-23 23:24:30 +0200937{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200938 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100939 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200940 struct hci_dev *hdev;
941 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 +0200942 int err, found;
943
944 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200945
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200946 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200947
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200948 if (len != sizeof(*cp))
949 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
950
951 hdev = hci_dev_get(index);
952 if (!hdev)
953 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
954
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800955 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200956
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200957 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
958 err = hci_uuids_clear(hdev);
959 goto unlock;
960 }
961
962 found = 0;
963
964 list_for_each_safe(p, n, &hdev->uuids) {
965 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
966
967 if (memcmp(match->uuid, cp->uuid, 16) != 0)
968 continue;
969
970 list_del(&match->list);
971 found++;
972 }
973
974 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200976 goto unlock;
977 }
978
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530979 if (test_bit(HCI_UP, &hdev->flags)) {
980 err = update_class(hdev);
981 if (err < 0)
982 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200983
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530984 err = update_eir(hdev);
985 if (err < 0)
986 goto unlock;
987 } else
988 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300989
Szymon Janc4e51eae2011-02-25 19:05:48 +0100990 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200991
992unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800993 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200994 hci_dev_put(hdev);
995
996 return err;
997}
998
Szymon Janc4e51eae2011-02-25 19:05:48 +0100999static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
1000 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001001{
1002 struct hci_dev *hdev;
1003 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004 int err;
1005
1006 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001007
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001009
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001010 if (len != sizeof(*cp))
1011 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001012
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001013 hdev = hci_dev_get(index);
1014 if (!hdev)
1015 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
1016
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001017 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018
Brian Gix8a7f1642011-10-17 17:39:46 -07001019 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1020 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001021 hdev->minor_class = cp->minor;
1022
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301023 if (test_bit(HCI_UP, &hdev->flags)) {
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301024 err = update_class(hdev);
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301025 if (err == 0)
1026 err = cmd_complete(sk, index,
1027 MGMT_OP_SET_DEV_CLASS, hdev->dev_class, sizeof(u8)*3);
1028 } else
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001030
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001031 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001032 hci_dev_put(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001033
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001034 return err;
1035}
1036
Johan Hedberg03811012010-12-08 00:21:06 +02001037static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1038 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001039{
Johan Hedberg03811012010-12-08 00:21:06 +02001040 struct hci_dev *hdev;
1041 struct mgmt_cp_set_service_cache *cp;
1042 int err;
1043
1044 cp = (void *) data;
1045
1046 if (len != sizeof(*cp))
1047 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
1048
1049 hdev = hci_dev_get(index);
1050 if (!hdev)
1051 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1052
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001053 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001054
1055 BT_DBG("hci%u enable %d", index, cp->enable);
1056
1057 if (cp->enable) {
1058 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1059 err = 0;
1060 } else {
1061 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301062 if (test_bit(HCI_UP, &hdev->flags)) {
1063 err = update_class(hdev);
1064 if (err == 0)
1065 err = update_eir(hdev);
1066 } else
1067 err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02001068 }
1069
1070 if (err == 0)
1071 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1072 0);
1073
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001074 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001075 hci_dev_put(hdev);
1076
1077 return err;
1078}
1079
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
1081{
1082 struct hci_dev *hdev;
1083 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001084 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001085 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086
1087 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001088
1089 if (len < sizeof(*cp))
1090 return -EINVAL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001091
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001092 key_count = get_unaligned_le16(&cp->key_count);
1093
1094 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001095 if (expected_len > len) {
1096 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1097 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001098 return -EINVAL;
1099 }
1100
Szymon Janc4e51eae2011-02-25 19:05:48 +01001101 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001102 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001104
Szymon Janc4e51eae2011-02-25 19:05:48 +01001105 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001106 key_count);
1107
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001108 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001109
1110 hci_link_keys_clear(hdev);
1111
1112 set_bit(HCI_LINK_KEYS, &hdev->flags);
1113
1114 if (cp->debug_keys)
1115 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1116 else
1117 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1118
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001119 len -= sizeof(*cp);
1120 i = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001121
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001122 while (i < len) {
1123 struct mgmt_key_info *key = (void *) cp->keys + i;
1124
Brian Gixa68668b2011-08-11 15:49:36 -07001125 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001126
Brian Gixcf956772011-10-20 15:18:51 -07001127 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001128 struct key_master_id *id = (void *) key->data;
1129
1130 if (key->dlen != sizeof(struct key_master_id))
1131 continue;
1132
Brian Gixcf956772011-10-20 15:18:51 -07001133 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1134 key->pin_len, key->auth, id->ediv,
1135 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001136
1137 continue;
1138 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001139
Brian Gixcf956772011-10-20 15:18:51 -07001140 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001141 key->pin_len);
1142 }
1143
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001144 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001145
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001146 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001147 hci_dev_put(hdev);
1148
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001149 return err;
1150}
1151
Johan Hedberg03811012010-12-08 00:21:06 +02001152static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001153{
Johan Hedberg03811012010-12-08 00:21:06 +02001154 struct hci_dev *hdev;
1155 struct mgmt_cp_remove_key *cp;
1156 struct hci_conn *conn;
1157 int err;
1158
1159 cp = (void *) data;
1160
1161 if (len != sizeof(*cp))
1162 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1163
1164 hdev = hci_dev_get(index);
1165 if (!hdev)
1166 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
1167
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001168 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001169
1170 err = hci_remove_link_key(hdev, &cp->bdaddr);
1171 if (err < 0) {
1172 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
1173 goto unlock;
1174 }
1175
1176 err = 0;
1177
1178 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1179 goto unlock;
1180
1181 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1182 if (conn) {
1183 struct hci_cp_disconnect dc;
1184
1185 put_unaligned_le16(conn->handle, &dc.handle);
1186 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02001188 }
1189
1190unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001191 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001192 hci_dev_put(hdev);
1193
1194 return err;
1195}
1196
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
1198{
1199 struct hci_dev *hdev;
1200 struct mgmt_cp_disconnect *cp;
1201 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001202 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001203 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204 int err;
1205
1206 BT_DBG("");
1207
1208 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001209
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001210 if (len != sizeof(*cp))
1211 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001214 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001216
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001217 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218
1219 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001220 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001221 goto failed;
1222 }
1223
Szymon Janc4e51eae2011-02-25 19:05:48 +01001224 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1225 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001226 goto failed;
1227 }
1228
1229 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1230 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001231 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1232 if (!conn) {
1233 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1234 ENOTCONN);
1235 goto failed;
1236 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001237 }
1238
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001240 if (!cmd) {
1241 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001242 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001243 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001244
1245 put_unaligned_le16(conn->handle, &dc.handle);
1246 dc.reason = 0x13; /* Remote User Terminated Connection */
1247
1248 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1249 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001250 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001251
1252failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001253 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001254 hci_dev_put(hdev);
1255
1256 return err;
1257}
1258
Szymon Janc8ce62842011-03-01 16:55:32 +01001259static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001260{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261 struct mgmt_rp_get_connections *rp;
1262 struct hci_dev *hdev;
1263 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001264 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266 int i, err;
1267
1268 BT_DBG("");
1269
Szymon Janc4e51eae2011-02-25 19:05:48 +01001270 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001271 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001272 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001273
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001274 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001275
1276 count = 0;
1277 list_for_each(p, &hdev->conn_hash.list) {
1278 count++;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001279 }
1280
Johan Hedberga38528f2011-01-22 06:46:43 +02001281 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1282 rp = kmalloc(rp_len, GFP_ATOMIC);
1283 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001284 err = -ENOMEM;
1285 goto unlock;
1286 }
1287
Johan Hedberg2784eb42011-01-21 13:56:35 +02001288 put_unaligned_le16(count, &rp->conn_count);
1289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290 read_lock(&hci_dev_list_lock);
1291
Johan Hedberg2784eb42011-01-21 13:56:35 +02001292 i = 0;
1293 list_for_each(p, &hdev->conn_hash.list) {
1294 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1295
1296 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001297 }
1298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 read_unlock(&hci_dev_list_lock);
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001300
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001302
1303unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001304 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001305 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001306 hci_dev_put(hdev);
1307 return err;
1308}
1309
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1311 u16 len)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001312{
Johan Hedberg980e1a52011-01-22 06:10:07 +02001313 struct hci_dev *hdev;
1314 struct mgmt_cp_pin_code_reply *cp;
1315 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001316 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317 int err;
1318
1319 BT_DBG("");
1320
1321 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001322
Johan Hedberg980e1a52011-01-22 06:10:07 +02001323 if (len != sizeof(*cp))
1324 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1325
1326 hdev = hci_dev_get(index);
1327 if (!hdev)
1328 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
1329
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001330 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001331
1332 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001333 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334 goto failed;
1335 }
1336
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001338 if (!cmd) {
1339 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001341 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001342
1343 bacpy(&reply.bdaddr, &cp->bdaddr);
1344 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346
1347 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1348 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001349 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350
1351failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001352 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001353 hci_dev_put(hdev);
1354
1355 return err;
1356}
1357
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301358static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1359 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001360{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301361 struct hci_dev *hdev;
1362 struct mgmt_cp_encrypt_link *cp;
1363 struct hci_cp_set_conn_encrypt enc;
1364 struct hci_conn *conn;
1365 int err = 0;
1366
1367 BT_DBG("");
1368
1369 cp = (void *) data;
1370
1371 if (len != sizeof(*cp))
1372 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1373
1374 hdev = hci_dev_get(index);
1375 if (!hdev)
1376 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1377
Brian Gix384ec672012-03-08 18:41:15 -08001378 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301379
1380 if (!test_bit(HCI_UP, &hdev->flags)) {
1381 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001382 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301383 }
1384
Brian Gix384ec672012-03-08 18:41:15 -08001385 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1386 if (!conn) {
1387 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1388 goto done;
1389 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301390
Brian Gix384ec672012-03-08 18:41:15 -08001391 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1392 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1393 goto done;
1394 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301395
1396 if (conn->link_mode & HCI_LM_AUTH) {
1397 enc.handle = cpu_to_le16(conn->handle);
1398 enc.encrypt = cp->enable;
1399 err = hci_send_cmd(hdev,
1400 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1401 } else {
1402 conn->auth_initiator = 1;
1403 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1404 struct hci_cp_auth_requested cp;
1405 cp.handle = cpu_to_le16(conn->handle);
1406 err = hci_send_cmd(conn->hdev,
1407 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1408 }
1409 }
1410
Brian Gix384ec672012-03-08 18:41:15 -08001411done:
1412 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301413 hci_dev_put(hdev);
1414
1415 return err;
1416}
1417
1418
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1420 u16 len)
1421{
1422 struct hci_dev *hdev;
1423 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001425 int err;
1426
1427 BT_DBG("");
1428
1429 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001430
Johan Hedberg980e1a52011-01-22 06:10:07 +02001431 if (len != sizeof(*cp))
1432 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1433 EINVAL);
1434
1435 hdev = hci_dev_get(index);
1436 if (!hdev)
1437 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1438 ENODEV);
1439
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001440 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001441
1442 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001443 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1444 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001445 goto failed;
1446 }
1447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1449 data, len);
1450 if (!cmd) {
1451 err = -ENOMEM;
1452 goto failed;
1453 }
1454
1455 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1456 &cp->bdaddr);
1457 if (err < 0)
1458 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001459
1460failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001461 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001462 hci_dev_put(hdev);
1463
1464 return err;
1465}
1466
Sunny Kapdi93bef892012-07-30 14:52:56 -07001467static int le_add_dev_white_list(struct sock *sk, u16 index,
1468 unsigned char *data, u16 len)
1469{
1470 struct hci_dev *hdev;
1471 struct mgmt_cp_le_add_dev_white_list *cp;
1472 int err = 0;
1473
1474 BT_DBG("");
1475
1476 cp = (void *) data;
1477
1478 if (len != sizeof(*cp))
1479 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1480 EINVAL);
1481
1482 hdev = hci_dev_get(index);
1483 if (!hdev)
1484 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1485 ENODEV);
1486
1487 hci_dev_lock_bh(hdev);
1488
1489 if (!test_bit(HCI_UP, &hdev->flags)) {
1490 err = cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1491 ENETDOWN);
1492 goto failed;
1493 }
1494
1495 hci_le_add_dev_white_list(hdev, &cp->bdaddr);
1496
1497failed:
1498 hci_dev_unlock_bh(hdev);
1499 hci_dev_put(hdev);
1500
1501 return err;
1502}
1503
1504static int le_remove_dev_white_list(struct sock *sk, u16 index,
1505 unsigned char *data, u16 len)
1506{
1507 struct hci_dev *hdev;
1508 struct mgmt_cp_le_remove_dev_white_list *cp;
1509 int err = 0;
1510
1511 BT_DBG("");
1512
1513 cp = (void *) data;
1514
1515 if (len != sizeof(*cp))
1516 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1517 EINVAL);
1518
1519 hdev = hci_dev_get(index);
1520 if (!hdev)
1521 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1522 ENODEV);
1523
1524 hci_dev_lock_bh(hdev);
1525
1526 if (!test_bit(HCI_UP, &hdev->flags)) {
1527 err = cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1528 ENETDOWN);
1529 goto failed;
1530 }
1531
1532 hci_le_remove_dev_white_list(hdev, &cp->bdaddr);
1533
1534failed:
1535 hci_dev_unlock_bh(hdev);
1536 hci_dev_put(hdev);
1537
1538 return err;
1539}
1540
1541static int le_create_conn_white_list(struct sock *sk, u16 index)
1542{
1543 struct hci_dev *hdev;
1544 struct hci_conn *conn;
1545 u8 sec_level, auth_type;
1546 struct pending_cmd *cmd;
1547 bdaddr_t bdaddr;
1548 int err = 0;
1549
1550 BT_DBG("");
1551
1552 hdev = hci_dev_get(index);
1553 if (!hdev)
1554 return cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1555 ENODEV);
1556
1557 hci_dev_lock_bh(hdev);
1558
1559 if (!test_bit(HCI_UP, &hdev->flags)) {
1560 err = cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1561 ENETDOWN);
1562 goto failed;
1563 }
1564
1565 cmd = mgmt_pending_add(sk, MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index,
1566 NULL, 0);
1567 if (!cmd) {
1568 err = -ENOMEM;
1569 goto failed;
1570 }
1571
1572 sec_level = BT_SECURITY_MEDIUM;
1573 auth_type = HCI_AT_GENERAL_BONDING;
1574 memset(&bdaddr, 0, sizeof(bdaddr));
1575 conn = hci_le_connect(hdev, 0, BDADDR_ANY, sec_level, auth_type, NULL);
1576 if (IS_ERR(conn)) {
1577 err = PTR_ERR(conn);
1578 mgmt_pending_remove(cmd);
1579 }
1580
1581failed:
1582 hci_dev_unlock_bh(hdev);
1583 hci_dev_put(hdev);
1584
1585 return err;
1586}
1587
1588static int le_cancel_create_conn_white_list(struct sock *sk, u16 index)
1589{
1590 struct hci_dev *hdev;
1591 int err = 0;
1592
1593 BT_DBG("");
1594
1595 hdev = hci_dev_get(index);
1596 if (!hdev)
1597 return cmd_status(sk, index,
1598 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENODEV);
1599
1600 hci_dev_lock_bh(hdev);
1601
1602 if (!test_bit(HCI_UP, &hdev->flags)) {
1603 err = cmd_status(sk, index,
1604 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENETDOWN);
1605 goto failed;
1606 }
1607
1608 hci_le_cancel_create_connect(hdev, BDADDR_ANY);
1609
1610failed:
1611 hci_dev_unlock_bh(hdev);
1612 hci_dev_put(hdev);
1613
1614 return err;
1615}
1616
1617static int le_clear_white_list(struct sock *sk, u16 index)
1618{
1619 struct hci_dev *hdev;
1620 int err;
1621
1622 BT_DBG("");
1623
1624 hdev = hci_dev_get(index);
1625 if (!hdev)
1626 return cmd_status(sk, index,
1627 MGMT_OP_LE_CLEAR_WHITE_LIST, ENODEV);
1628
1629 hci_dev_lock_bh(hdev);
1630
1631 if (!test_bit(HCI_UP, &hdev->flags)) {
1632 err = cmd_status(sk, index,
1633 MGMT_OP_LE_CLEAR_WHITE_LIST, ENETDOWN);
1634 goto failed;
1635 }
1636
1637 err = hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
1638
1639failed:
1640 hci_dev_unlock_bh(hdev);
1641 hci_dev_put(hdev);
1642
1643 return err;
1644}
1645
Szymon Janc4e51eae2011-02-25 19:05:48 +01001646static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1647 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001648{
1649 struct hci_dev *hdev;
1650 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001651
1652 BT_DBG("");
1653
1654 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001655
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001656 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001657 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001658
Szymon Janc4e51eae2011-02-25 19:05:48 +01001659 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001660 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001661 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001662
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001663 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001664
1665 hdev->io_capability = cp->io_capability;
1666
1667 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001668 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001669
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001670 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001671 hci_dev_put(hdev);
1672
Szymon Janc4e51eae2011-02-25 19:05:48 +01001673 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001674}
1675
Johan Hedberge9a416b2011-02-19 12:05:56 -03001676static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1677{
1678 struct hci_dev *hdev = conn->hdev;
1679 struct list_head *p;
1680
1681 list_for_each(p, &cmd_list) {
1682 struct pending_cmd *cmd;
1683
1684 cmd = list_entry(p, struct pending_cmd, list);
1685
1686 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1687 continue;
1688
1689 if (cmd->index != hdev->id)
1690 continue;
1691
1692 if (cmd->user_data != conn)
1693 continue;
1694
1695 return cmd;
1696 }
1697
1698 return NULL;
1699}
1700
1701static void pairing_complete(struct pending_cmd *cmd, u8 status)
1702{
1703 struct mgmt_rp_pair_device rp;
1704 struct hci_conn *conn = cmd->user_data;
1705
Brian Gixa68668b2011-08-11 15:49:36 -07001706 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001707
Johan Hedberge9a416b2011-02-19 12:05:56 -03001708 bacpy(&rp.bdaddr, &conn->dst);
1709 rp.status = status;
1710
Szymon Janc4e51eae2011-02-25 19:05:48 +01001711 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001712
1713 /* So we don't get further callbacks for this connection */
1714 conn->connect_cfm_cb = NULL;
1715 conn->security_cfm_cb = NULL;
1716 conn->disconn_cfm_cb = NULL;
1717
Johan Hedberga664b5b2011-02-19 12:06:02 -03001718 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001719}
1720
1721static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1722{
1723 struct pending_cmd *cmd;
1724
Brian Gixa68668b2011-08-11 15:49:36 -07001725 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001727 cmd = find_pairing(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001728 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001729 BT_DBG("Unable to find a pending command");
Johan Hedberge9a416b2011-02-19 12:05:56 -03001730 return;
1731 }
1732
1733 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001734 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001735}
1736
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001737static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001738{
Johan Hedberge9a416b2011-02-19 12:05:56 -03001739 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001740
1741 BT_DBG(" %u", status);
1742
1743 cmd = find_pairing(conn);
1744 if (!cmd) {
1745 BT_DBG("Unable to find a pending command");
1746 return;
1747 }
1748
1749 if (conn->type == LE_LINK)
1750 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1751 status ? 0 : 1);
1752 else
1753 pairing_complete(cmd, status);
1754}
1755
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001756static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001757{
1758 struct pending_cmd *cmd;
1759
1760 BT_DBG("conn: %p %u", conn, status);
1761
1762 cmd = find_pairing(conn);
1763 if (!cmd) {
1764 BT_DBG("Unable to find a pending command");
1765 return;
1766 }
Brian Gix114f3a62011-09-27 14:02:20 -07001767
Srinivas Krovvidi52b05ba2012-08-27 18:32:45 +05301768 if (status || conn->pending_sec_level < BT_SECURITY_MEDIUM)
Brian Gix114f3a62011-09-27 14:02:20 -07001769 pairing_complete(cmd, status);
1770
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001771 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001772}
1773
1774static void discovery_terminated(struct pending_cmd *cmd, void *data)
1775{
Brian Gix6e349d02011-11-28 14:51:14 -08001776 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001777 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001778
1779 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001780 hdev = hci_dev_get(cmd->index);
1781 if (!hdev)
1782 goto not_found;
1783
Brian Gix568dde92012-01-11 16:18:04 -08001784 del_timer(&hdev->disco_le_timer);
1785 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001786 hci_dev_put(hdev);
1787
1788not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001789 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1790
1791 list_del(&cmd->list);
1792
1793 mgmt_pending_free(cmd);
1794}
1795
Johan Hedberge9a416b2011-02-19 12:05:56 -03001796static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
1797{
1798 struct hci_dev *hdev;
1799 struct mgmt_cp_pair_device *cp;
1800 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001801 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001802 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001803 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001804 int err;
1805
1806 BT_DBG("");
1807
Brian Gix64bd5302011-09-08 11:35:48 -07001808 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809
Brian Gix64bd5302011-09-08 11:35:48 -07001810 if (len != sizeof(*cp))
1811 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1812
Johan Hedberge9a416b2011-02-19 12:05:56 -03001813 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001814
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815 if (!hdev)
1816 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
1817
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001818 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001819
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301820 io_cap = cp->io_cap;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001821
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001822 sec_level = BT_SECURITY_MEDIUM;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301823 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824
Brian Gixfdd38922011-09-28 16:23:48 -07001825 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1826 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001827 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1828 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001829 } else {
1830 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1831 if (io_cap == 0x04)
1832 io_cap = 0x01;
1833 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1834 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301835 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001836 }
Johan Hedberg1425acb2011-11-11 00:07:35 +02001837
Ville Tervo30e76272011-02-22 16:10:53 -03001838 if (IS_ERR(conn)) {
1839 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001840 goto unlock;
1841 }
1842
1843 if (conn->connect_cfm_cb) {
1844 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 goto unlock;
1847 }
1848
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001850 if (!cmd) {
1851 err = -ENOMEM;
1852 hci_conn_put(conn);
1853 goto unlock;
1854 }
1855
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001856 conn->connect_cfm_cb = pairing_connect_complete_cb;
1857 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001859 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001860 cmd->user_data = conn;
1861
1862 if (conn->state == BT_CONNECTED &&
1863 hci_conn_security(conn, sec_level, auth_type))
1864 pairing_complete(cmd, 0);
1865
1866 err = 0;
1867
1868unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001869 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001870 hci_dev_put(hdev);
1871
1872 return err;
1873}
1874
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001876 u16 len, u16 opcode)
Johan Hedberg28424702012-02-02 04:02:29 +02001877{
Johan Hedberga5c29682011-02-19 12:05:57 -03001878 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001879 u16 mgmt_op = opcode, hci_op;
Johan Hedberg28424702012-02-02 04:02:29 +02001880 struct pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03001881 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001882 struct hci_conn *le_conn;
Johan Hedberg28424702012-02-02 04:02:29 +02001883 int err;
1884
Brian Gixa68668b2011-08-11 15:49:36 -07001885 BT_DBG("%d", mgmt_op);
Johan Hedberg28424702012-02-02 04:02:29 +02001886
Brian Gixa68668b2011-08-11 15:49:36 -07001887 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001888 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Johan Hedberg272d90d2012-02-09 15:26:12 +02001889 else
Brian Gixa68668b2011-08-11 15:49:36 -07001890 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Brian Gix47c15e22011-11-16 13:53:14 -08001891
Brian Gixa68668b2011-08-11 15:49:36 -07001892 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001893 return cmd_status(sk, index, mgmt_op, EINVAL);
1894
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001896 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001897 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001898
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001899 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001900
Johan Hedberga5c29682011-02-19 12:05:57 -03001901 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberg272d90d2012-02-09 15:26:12 +02001903 goto done;
1904 }
1905
Brian Gixa68668b2011-08-11 15:49:36 -07001906 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1907 if (le_conn) {
1908 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
Brian Gix47c15e22011-11-16 13:53:14 -08001909 goto done;
1910 }
Brian Gixa68668b2011-08-11 15:49:36 -07001911 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1912 "Reject" : "Accept");
Brian Gix47c15e22011-11-16 13:53:14 -08001913
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 if (!cmd) {
1916 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001917 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001918 }
1919
Brian Gixa68668b2011-08-11 15:49:36 -07001920 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001921 if (err < 0)
1922 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001923
Brian Gix0df4c182011-11-16 13:53:13 -08001924done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001925 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001926 hci_dev_put(hdev);
1927
Johan Hedberga5c29682011-02-19 12:05:57 -03001928 return err;
1929}
1930
Brian Gixa68668b2011-08-11 15:49:36 -07001931static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1932 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08001933{
Brian Gixa68668b2011-08-11 15:49:36 -07001934 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1935 struct hci_cp_remote_name_req hci_cp;
1936 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001937 struct pending_cmd *cmd;
1938 int err;
1939
1940 BT_DBG("");
1941
Brian Gixa68668b2011-08-11 15:49:36 -07001942 if (len != sizeof(*mgmt_cp))
1943 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001944
Brian Gixa68668b2011-08-11 15:49:36 -07001945 hdev = hci_dev_get(index);
1946 if (!hdev)
1947 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001948
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001949 hci_dev_lock_bh(hdev);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001950
Brian Gixa68668b2011-08-11 15:49:36 -07001951 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001952 if (!cmd) {
1953 err = -ENOMEM;
1954 goto failed;
1955 }
1956
Brian Gixa68668b2011-08-11 15:49:36 -07001957 memset(&hci_cp, 0, sizeof(hci_cp));
1958 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1959 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1960 &hci_cp);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001961 if (err < 0)
1962 mgmt_pending_remove(cmd);
1963
1964failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001965 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001966 hci_dev_put(hdev);
1967
Johan Hedbergb312b1612011-03-16 14:29:37 +02001968 return err;
1969}
1970
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05301971static int cancel_resolve_name(struct sock *sk, u16 index, unsigned char *data,
1972 u16 len)
1973{
1974 struct mgmt_cp_cancel_resolve_name *mgmt_cp = (void *) data;
1975 struct hci_cp_remote_name_req_cancel hci_cp;
1976 struct hci_dev *hdev;
1977 int err;
1978
1979 BT_DBG("");
1980
1981 if (len != sizeof(*mgmt_cp))
1982 return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
1983 EINVAL);
1984
1985 hdev = hci_dev_get(index);
1986 if (!hdev)
1987 return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
1988 ENODEV);
1989
1990 hci_dev_lock_bh(hdev);
1991
1992 memset(&hci_cp, 0, sizeof(hci_cp));
1993 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1994 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(hci_cp),
1995 &hci_cp);
1996
1997 hci_dev_unlock_bh(hdev);
1998 hci_dev_put(hdev);
1999
2000 return err;
2001}
2002
Brian Gix7f7e16c2011-11-01 16:27:25 -07002003static int set_connection_params(struct sock *sk, u16 index,
2004 unsigned char *data, u16 len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002005{
Brian Gix7f7e16c2011-11-01 16:27:25 -07002006 struct mgmt_cp_set_connection_params *cp = (void *) data;
2007 struct hci_dev *hdev;
2008 struct hci_conn *conn;
2009 int err;
2010
2011 BT_DBG("");
2012
2013 if (len != sizeof(*cp))
2014 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2015 EINVAL);
2016
2017 hdev = hci_dev_get(index);
2018 if (!hdev)
2019 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2020 ENODEV);
2021
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002022 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07002023
2024 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2025 if (!conn) {
2026 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2027 ENOTCONN);
2028 goto failed;
2029 }
2030
2031 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
2032 le16_to_cpu(cp->interval_max),
2033 le16_to_cpu(cp->slave_latency),
2034 le16_to_cpu(cp->timeout_multiplier));
2035
2036 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
2037
2038failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002039 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07002040 hci_dev_put(hdev);
2041
2042 return err;
2043}
2044
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002045static int set_rssi_reporter(struct sock *sk, u16 index,
2046 unsigned char *data, u16 len)
2047{
2048 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
2049 struct hci_dev *hdev;
2050 struct hci_conn *conn;
2051 int err = 0;
2052
2053 if (len != sizeof(*cp))
2054 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2055 EINVAL);
2056
2057 hdev = hci_dev_get(index);
2058 if (!hdev)
2059 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2060 ENODEV);
2061
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002062 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002063
2064 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2065
2066 if (!conn) {
2067 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2068 ENOTCONN);
2069 goto failed;
2070 }
2071
2072 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
2073 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
2074 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
2075
2076failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002077 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002078 hci_dev_put(hdev);
2079
2080 return err;
2081}
2082
2083static int unset_rssi_reporter(struct sock *sk, u16 index,
2084 unsigned char *data, u16 len)
2085{
2086 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
2087 struct hci_dev *hdev;
2088 struct hci_conn *conn;
2089 int err = 0;
2090
2091 if (len != sizeof(*cp))
2092 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2093 EINVAL);
2094
2095 hdev = hci_dev_get(index);
2096
2097 if (!hdev)
2098 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2099 ENODEV);
2100
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002101 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002102
2103 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2104
2105 if (!conn) {
2106 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2107 ENOTCONN);
2108 goto failed;
2109 }
2110
2111 hci_conn_unset_rssi_reporter(conn);
2112
2113failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002114 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002115 hci_dev_put(hdev);
2116
2117 return err;
2118}
2119
Archana Ramachandran907d5232012-10-02 17:55:55 -07002120static int le_cancel_create_conn(struct sock *sk, u16 index,
2121 unsigned char *data, u16 len)
2122{
2123 struct mgmt_cp_le_cancel_create_conn *cp = (void *) data;
2124 struct hci_dev *hdev;
2125 int err = 0;
2126
2127 if (len != sizeof(*cp))
2128 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2129 EINVAL);
2130
2131 hdev = hci_dev_get(index);
2132
2133 if (!hdev)
2134 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2135 ENODEV);
2136
2137 hci_dev_lock_bh(hdev);
2138
2139 if (!test_bit(HCI_UP, &hdev->flags)) {
2140 err = cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2141 ENETDOWN);
2142 goto failed;
2143 }
2144
2145 hci_le_cancel_create_connect(hdev, &cp->bdaddr);
2146
2147failed:
2148 hci_dev_unlock_bh(hdev);
2149 hci_dev_put(hdev);
2150
2151return err;
2152}
2153
Johan Hedberg03811012010-12-08 00:21:06 +02002154static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
2155 u16 len)
2156{
2157 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
2158 struct hci_cp_write_local_name hci_cp;
2159 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01002160 struct pending_cmd *cmd;
2161 int err;
2162
Johan Hedberg03811012010-12-08 00:21:06 +02002163 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01002164
Johan Hedberg03811012010-12-08 00:21:06 +02002165 if (len != sizeof(*mgmt_cp))
2166 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01002167
Johan Hedberg03811012010-12-08 00:21:06 +02002168 hdev = hci_dev_get(index);
2169 if (!hdev)
2170 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
2171
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002172 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002173
2174 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
2175 if (!cmd) {
2176 err = -ENOMEM;
2177 goto failed;
2178 }
2179
2180 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2181 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2182 &hci_cp);
2183 if (err < 0)
2184 mgmt_pending_remove(cmd);
2185
2186failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002187 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002188 hci_dev_put(hdev);
2189
2190 return err;
2191}
2192
Brian Gixa68668b2011-08-11 15:49:36 -07002193static void discovery_rsp(struct pending_cmd *cmd, void *data)
2194{
2195 struct mgmt_mode ev;
2196
2197 BT_DBG("");
2198 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
2199 ev.val = 1;
2200 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
2201 } else {
2202 ev.val = 0;
2203 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
2204 NULL, 0);
2205 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08002206 struct hci_dev *hdev = hci_dev_get(cmd->index);
2207 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08002208 del_timer(&hdev->disco_le_timer);
2209 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08002210 hci_dev_put(hdev);
2211 }
Brian Gixa68668b2011-08-11 15:49:36 -07002212 }
2213 }
2214
2215 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
2216
2217 list_del(&cmd->list);
2218
2219 mgmt_pending_free(cmd);
2220}
2221
2222void mgmt_inquiry_started(u16 index)
2223{
2224 BT_DBG("");
2225 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
2226 discovery_rsp, NULL);
2227}
2228
2229void mgmt_inquiry_complete_evt(u16 index, u8 status)
2230{
2231 struct hci_dev *hdev;
2232 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08002233 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002234 int err = -1;
2235
Brian Gixa68668b2011-08-11 15:49:36 -07002236 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07002237
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302238 if (hdev)
2239 BT_DBG("disco_state: %d", hdev->disco_state);
2240
Brian Gixa68668b2011-08-11 15:49:36 -07002241 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07002242
2243 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2244 discovery_terminated, NULL);
2245
2246 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002247
Anantha Krishnan91b11ff2013-01-27 18:20:20 +05302248 if (hdev) {
2249 BT_DBG("Setting state to SCAN_IDLE\n");
2250 hdev->disco_state = SCAN_IDLE;
Brian Gix64bd5302011-09-08 11:35:48 -07002251 goto done;
Anantha Krishnan91b11ff2013-01-27 18:20:20 +05302252 }
Brian Gix64bd5302011-09-08 11:35:48 -07002253 else
2254 return;
2255 }
Brian Gixa68668b2011-08-11 15:49:36 -07002256
Brian Gix568dde92012-01-11 16:18:04 -08002257 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002258 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2259 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002260 if (err >= 0) {
2261 mod_timer(&hdev->disco_le_timer, jiffies +
2262 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2263 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002264 } else
Brian Gix568dde92012-01-11 16:18:04 -08002265 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002266 }
2267
Brian Gix568dde92012-01-11 16:18:04 -08002268 if (hdev->disco_state == SCAN_IDLE)
2269 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2270
Brian Gixa68668b2011-08-11 15:49:36 -07002271 if (err < 0)
2272 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2273 discovery_terminated, NULL);
2274
Brian Gix64bd5302011-09-08 11:35:48 -07002275done:
Brian Gixa68668b2011-08-11 15:49:36 -07002276 hci_dev_put(hdev);
2277}
2278
Brian Gix568dde92012-01-11 16:18:04 -08002279void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002280{
Brian Gix568dde92012-01-11 16:18:04 -08002281 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002282 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002283 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002284
Brian Gix568dde92012-01-11 16:18:04 -08002285 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002286
Brian Gix568dde92012-01-11 16:18:04 -08002287 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002288
Brian Gix568dde92012-01-11 16:18:04 -08002289 if (!hdev)
2290 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002291
Brian Gix568dde92012-01-11 16:18:04 -08002292 hci_dev_lock_bh(hdev);
2293 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002294
Brian Gix568dde92012-01-11 16:18:04 -08002295 if (hdev->disco_state != SCAN_IDLE) {
2296 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002297
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302298 if (test_bit(HCI_UP, &hdev->flags)) {
2299 if (hdev->disco_state == SCAN_LE)
2300 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002301 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302302 else
2303 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2304 NULL);
2305 }
Brian Gix568dde92012-01-11 16:18:04 -08002306 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002307 }
Brian Gix568dde92012-01-11 16:18:04 -08002308
2309 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2310
2311 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2312 if (cmd)
2313 mgmt_pending_remove(cmd);
2314
2315 hci_dev_unlock_bh(hdev);
2316 hci_dev_put(hdev);
2317}
2318
2319void mgmt_disco_le_timeout(unsigned long data)
2320{
2321 struct hci_dev *hdev = (void *)data;
2322 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2323
2324 BT_DBG("hci%d", hdev->id);
2325
2326 hdev = hci_dev_get(hdev->id);
2327
2328 if (!hdev)
2329 return;
2330
2331 hci_dev_lock_bh(hdev);
2332
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302333 if (test_bit(HCI_UP, &hdev->flags)) {
2334 if (hdev->disco_state == SCAN_LE)
2335 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2336 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002337
2338 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302339 if (hdev->disco_state != SCAN_IDLE) {
2340 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2341 hdev->disco_int_phase *= 2;
2342 hdev->disco_int_count = 0;
2343 cp.num_rsp = (u8) hdev->disco_int_phase;
2344 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2345 hdev->disco_state = SCAN_BR;
2346 }
Brian Gix568dde92012-01-11 16:18:04 -08002347 }
2348
2349 hci_dev_unlock_bh(hdev);
2350 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002351}
2352
2353static int start_discovery(struct sock *sk, u16 index)
2354{
2355 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2356 struct hci_dev *hdev;
2357 struct pending_cmd *cmd;
2358 int err;
2359
2360 BT_DBG("");
2361
2362 hdev = hci_dev_get(index);
2363 if (!hdev)
2364 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2365
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302366 BT_DBG("disco_state: %d", hdev->disco_state);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002367 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002368
Brian Gix568dde92012-01-11 16:18:04 -08002369 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2370 err = -EBUSY;
2371 goto failed;
2372 }
2373
Brian Gixa68668b2011-08-11 15:49:36 -07002374 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2375 if (!cmd) {
2376 err = -ENOMEM;
2377 goto failed;
2378 }
2379
2380 /* If LE Capable, we will alternate between BR/EDR and LE */
2381 if (lmp_le_capable(hdev)) {
2382 struct hci_cp_le_set_scan_parameters le_cp;
2383
2384 /* Shorten BR scan params */
2385 cp.num_rsp = 1;
2386 cp.length /= 2;
2387
2388 /* Setup LE scan params */
2389 memset(&le_cp, 0, sizeof(le_cp));
2390 le_cp.type = 0x01; /* Active scanning */
2391 /* The recommended value for scan interval and window is
2392 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2393 le_cp.interval = cpu_to_le16(0x0012);
2394 le_cp.window = cpu_to_le16(0x0012);
2395 le_cp.own_bdaddr_type = 0; /* Public address */
2396 le_cp.filter = 0; /* Accept all adv packets */
2397
2398 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2399 sizeof(le_cp), &le_cp);
2400 }
2401
2402 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2403
Bhasker Neti09760742012-05-25 12:30:39 +05302404 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002405 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302406 hdev->disco_state = SCAN_IDLE;
2407 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002408 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2409 if (!cmd)
2410 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2411 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002412 hdev->disco_int_phase = 1;
2413 hdev->disco_int_count = 0;
2414 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002415 del_timer(&hdev->disco_le_timer);
2416 del_timer(&hdev->disco_timer);
2417 mod_timer(&hdev->disco_timer,
2418 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302419 } else
2420 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002421
2422failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002423 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002424 hci_dev_put(hdev);
2425
Brian Gix568dde92012-01-11 16:18:04 -08002426 if (err < 0)
2427 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2428
Brian Gixa68668b2011-08-11 15:49:36 -07002429 return err;
2430}
2431
2432static int stop_discovery(struct sock *sk, u16 index)
2433{
2434 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2435 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002436 struct hci_dev *hdev;
2437 struct pending_cmd *cmd = NULL;
2438 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002439 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002440
2441 BT_DBG("");
2442
2443 hdev = hci_dev_get(index);
2444 if (!hdev)
2445 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2446
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302447 BT_DBG("disco_state: %d", hdev->disco_state);
2448
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002449 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002450
Brian Gix568dde92012-01-11 16:18:04 -08002451 state = hdev->disco_state;
2452 hdev->disco_state = SCAN_IDLE;
2453 del_timer(&hdev->disco_le_timer);
2454 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002455
Brian Gix568dde92012-01-11 16:18:04 -08002456 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002457 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2458 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002459 if (err >= 0) {
2460 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2461 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002462
Brian Gix568dde92012-01-11 16:18:04 -08002463 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2464 NULL, 0);
2465 }
Bhasker Neti09760742012-05-25 12:30:39 +05302466 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002467 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002468
Brian Gix568dde92012-01-11 16:18:04 -08002469 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002470 if (err < 0 && cmd)
2471 mgmt_pending_remove(cmd);
2472
2473 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2474
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002475 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002476 hci_dev_put(hdev);
2477
2478 if (err < 0)
2479 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2480 else
2481 return err;
2482}
2483
Szymon Jancc35938b2011-03-22 13:12:21 +01002484static int read_local_oob_data(struct sock *sk, u16 index)
2485{
2486 struct hci_dev *hdev;
2487 struct pending_cmd *cmd;
2488 int err;
2489
2490 BT_DBG("hci%u", index);
2491
2492 hdev = hci_dev_get(index);
2493 if (!hdev)
2494 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2495 ENODEV);
2496
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002497 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002498
2499 if (!test_bit(HCI_UP, &hdev->flags)) {
2500 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2501 ENETDOWN);
2502 goto unlock;
2503 }
2504
2505 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2506 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2507 EOPNOTSUPP);
2508 goto unlock;
2509 }
2510
2511 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2512 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2513 goto unlock;
2514 }
2515
2516 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2517 if (!cmd) {
2518 err = -ENOMEM;
2519 goto unlock;
2520 }
2521
2522 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2523 if (err < 0)
2524 mgmt_pending_remove(cmd);
2525
2526unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002527 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002528 hci_dev_put(hdev);
2529
2530 return err;
2531}
2532
Szymon Janc2763eda2011-03-22 13:12:22 +01002533static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2534 u16 len)
2535{
2536 struct hci_dev *hdev;
2537 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2538 int err;
2539
2540 BT_DBG("hci%u ", index);
2541
2542 if (len != sizeof(*cp))
2543 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2544 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002545
Szymon Janc2763eda2011-03-22 13:12:22 +01002546 hdev = hci_dev_get(index);
2547 if (!hdev)
2548 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2549 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002550
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002551 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002552
2553 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2554 cp->randomizer);
2555 if (err < 0)
2556 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2557 else
2558 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2559 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002560
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002561 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002562 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002563
Szymon Janc2763eda2011-03-22 13:12:22 +01002564 return err;
2565}
2566
2567static int remove_remote_oob_data(struct sock *sk, u16 index,
2568 unsigned char *data, u16 len)
2569{
2570 struct hci_dev *hdev;
2571 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2572 int err;
2573
2574 BT_DBG("hci%u ", index);
2575
2576 if (len != sizeof(*cp))
2577 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2578 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002579
Szymon Janc2763eda2011-03-22 13:12:22 +01002580 hdev = hci_dev_get(index);
2581 if (!hdev)
2582 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2583 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002584
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002585 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002586
2587 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2588 if (err < 0)
2589 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2590 -err);
2591 else
2592 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2593 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002594
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002595 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002596 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002597
2598 return err;
2599}
2600
Johan Hedberg03811012010-12-08 00:21:06 +02002601int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2602{
2603 unsigned char *buf;
2604 struct mgmt_hdr *hdr;
2605 u16 opcode, index, len;
2606 int err;
2607
2608 BT_DBG("got %zu bytes", msglen);
2609
2610 if (msglen < sizeof(*hdr))
2611 return -EINVAL;
2612
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002613 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002614 if (!buf)
2615 return -ENOMEM;
2616
2617 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2618 err = -EFAULT;
2619 goto done;
2620 }
2621
2622 hdr = (struct mgmt_hdr *) buf;
2623 opcode = get_unaligned_le16(&hdr->opcode);
2624 index = get_unaligned_le16(&hdr->index);
2625 len = get_unaligned_le16(&hdr->len);
2626
2627 if (len != msglen - sizeof(*hdr)) {
2628 err = -EINVAL;
2629 goto done;
2630 }
2631
Brian Gixa68668b2011-08-11 15:49:36 -07002632 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002633 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002634 case MGMT_OP_READ_VERSION:
2635 err = read_version(sk);
2636 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002637 case MGMT_OP_READ_INDEX_LIST:
2638 err = read_index_list(sk);
2639 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002640 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002641 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002642 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002643 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002644 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002645 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002646 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002647 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002648 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002649 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2650 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2651 len);
2652 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002653 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002654 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002655 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002656 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002657 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002658 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002659 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002660 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002661 break;
2662 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002663 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002664 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002665 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002666 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002667 break;
2668 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002669 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002670 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002671 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002672 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002673 break;
2674 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002675 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002676 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002677 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002678 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002679 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002680 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002681 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002682 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002683 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002684 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002685 break;
2686 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002687 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002688 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002689 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002690 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002691 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002692 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002693 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002694 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002695 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002696 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002697 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002698 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2699 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002700 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002701 case MGMT_OP_SET_LOCAL_NAME:
2702 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2703 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002704 case MGMT_OP_START_DISCOVERY:
2705 err = start_discovery(sk, index);
2706 break;
2707 case MGMT_OP_STOP_DISCOVERY:
2708 err = stop_discovery(sk, index);
2709 break;
2710 case MGMT_OP_RESOLVE_NAME:
2711 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2712 break;
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302713 case MGMT_OP_CANCEL_RESOLVE_NAME:
2714 err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
2715 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002716 case MGMT_OP_SET_CONNECTION_PARAMS:
2717 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2718 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002719 case MGMT_OP_SET_RSSI_REPORTER:
2720 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2721 break;
2722 case MGMT_OP_UNSET_RSSI_REPORTER:
2723 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2724 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002725 case MGMT_OP_READ_LOCAL_OOB_DATA:
2726 err = read_local_oob_data(sk, index);
2727 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002728 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2729 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2730 break;
2731 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2732 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2733 len);
2734 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302735 case MGMT_OP_ENCRYPT_LINK:
2736 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2737 break;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002738 case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
2739 err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
2740 len);
2741 break;
2742 case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
2743 err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
2744 len);
2745 break;
2746 case MGMT_OP_LE_CLEAR_WHITE_LIST:
2747 err = le_clear_white_list(sk, index);
2748 break;
2749 case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
2750 err = le_create_conn_white_list(sk, index);
2751 break;
2752 case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
2753 err = le_cancel_create_conn_white_list(sk, index);
2754 break;
Archana Ramachandran907d5232012-10-02 17:55:55 -07002755 case MGMT_OP_LE_CANCEL_CREATE_CONN:
2756 err = le_cancel_create_conn(sk, index, buf + sizeof(*hdr), len);
2757 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002758 default:
2759 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002760 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002761 break;
2762 }
2763
Johan Hedberge41d8b42010-12-13 21:07:03 +02002764 if (err < 0)
2765 goto done;
2766
Johan Hedberg03811012010-12-08 00:21:06 +02002767 err = msglen;
2768
2769done:
2770 kfree(buf);
2771 return err;
2772}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002773
Johan Hedbergb24752f2011-11-03 14:40:33 +02002774static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2775{
2776 u8 *status = data;
2777
2778 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2779 mgmt_pending_remove(cmd);
2780}
2781
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002782int mgmt_index_added(u16 index)
2783{
Brian Gixa68668b2011-08-11 15:49:36 -07002784 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002785 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002786}
2787
2788int mgmt_index_removed(u16 index)
2789{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002790 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002791
Brian Gixa68668b2011-08-11 15:49:36 -07002792 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002793
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002794 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2795
Szymon Janc4e51eae2011-02-25 19:05:48 +01002796 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002797}
2798
Johan Hedberg73f22f62010-12-29 16:00:25 +02002799struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002800 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002801 struct sock *sk;
2802};
2803
Johan Hedberg72a734e2010-12-30 00:38:22 +02002804static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002805{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002806 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002807 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002808
Johan Hedberg72a734e2010-12-30 00:38:22 +02002809 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002810 return;
2811
Johan Hedberg053f0212011-01-26 13:07:10 +02002812 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002813
2814 list_del(&cmd->list);
2815
2816 if (match->sk == NULL) {
2817 match->sk = cmd->sk;
2818 sock_hold(match->sk);
2819 }
2820
2821 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002822}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002823
2824int mgmt_powered(u16 index, u8 powered)
2825{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002826 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002827 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002828 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002829
Brian Gixa68668b2011-08-11 15:49:36 -07002830 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002831
Johan Hedberg72a734e2010-12-30 00:38:22 +02002832 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002833
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002834 if (!powered) {
2835 u8 status = ENETDOWN;
2836 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002837 }
2838
Johan Hedberg72a734e2010-12-30 00:38:22 +02002839 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002840
Szymon Janc4e51eae2011-02-25 19:05:48 +01002841 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002842
2843 if (match.sk)
2844 sock_put(match.sk);
2845
2846 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002847}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002848
Johan Hedberg73f22f62010-12-29 16:00:25 +02002849int mgmt_discoverable(u16 index, u8 discoverable)
2850{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002851 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002852 struct cmd_lookup match = { discoverable, NULL };
2853 int ret;
2854
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002855 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002856
Johan Hedberg73f22f62010-12-29 16:00:25 +02002857 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002858
Szymon Janc4e51eae2011-02-25 19:05:48 +01002859 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2860 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002861
Johan Hedberg73f22f62010-12-29 16:00:25 +02002862 if (match.sk)
2863 sock_put(match.sk);
2864
2865 return ret;
2866}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002867
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002868int mgmt_connectable(u16 index, u8 connectable)
2869{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002870 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002871 struct cmd_lookup match = { connectable, NULL };
2872 int ret;
2873
Johan Hedberg72a734e2010-12-30 00:38:22 +02002874 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002875
Johan Hedberg03811012010-12-08 00:21:06 +02002876 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002877
Szymon Janc4e51eae2011-02-25 19:05:48 +01002878 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002879
2880 if (match.sk)
2881 sock_put(match.sk);
2882
2883 return ret;
2884}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002885
Brian Gixa68668b2011-08-11 15:49:36 -07002886int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002887{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002888 struct mgmt_ev_new_key *ev;
2889 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002890
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002891 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2892 ev = kzalloc(total, GFP_ATOMIC);
2893 if (!ev)
2894 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002895
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002896 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002897 ev->key.addr_type = key->addr_type;
2898 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002899 memcpy(ev->key.val, key->val, 16);
2900 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002901 ev->key.auth = key->auth;
2902 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002903 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002904
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002905 memcpy(ev->key.data, key->data, key->dlen);
2906
2907 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2908
2909 kfree(ev);
2910
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002911 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002912}
2913
Brian Gix2e2f50d2011-09-13 12:36:04 -07002914int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002915{
Johan Hedbergf7520542011-01-20 12:34:39 +02002916 struct mgmt_ev_connected ev;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002917 struct pending_cmd *cmd;
2918 struct hci_dev *hdev;
2919
2920 BT_DBG("hci%u", index);
2921
2922 hdev = hci_dev_get(index);
2923
2924 if (!hdev)
2925 return -ENODEV;
Johan Hedbergca69b792011-11-11 18:10:00 +02002926
Johan Hedbergf7520542011-01-20 12:34:39 +02002927 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002928 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002929
Sunny Kapdi93bef892012-07-30 14:52:56 -07002930 cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
2931 if (cmd) {
2932 BT_ERR("mgmt_connected remove mgmt pending white_list");
2933 mgmt_pending_remove(cmd);
2934 }
2935
Szymon Janc4e51eae2011-02-25 19:05:48 +01002936 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002937}
2938
Sunny Kapdia42b5022012-07-05 22:48:31 -07002939int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
2940 u16 latency, u16 timeout)
2941{
2942 struct mgmt_ev_le_conn_params ev;
2943
2944 bacpy(&ev.bdaddr, bdaddr);
2945 ev.interval = interval;
2946 ev.latency = latency;
2947 ev.timeout = timeout;
2948
2949 return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
2950 NULL);
2951}
2952
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2954{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002955 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002957 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002958
Johan Hedberga38528f2011-01-22 06:46:43 +02002959 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002960
Szymon Janc4e51eae2011-02-25 19:05:48 +01002961 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002962
2963 *sk = cmd->sk;
2964 sock_hold(*sk);
2965
Johan Hedberga664b5b2011-02-19 12:06:02 -03002966 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002967}
2968
Archana Ramachandranda09d262012-08-14 12:03:01 -07002969int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002970{
Johan Hedbergf7520542011-01-20 12:34:39 +02002971 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002972 struct sock *sk = NULL;
2973 int err;
2974
Johan Hedbergf7520542011-01-20 12:34:39 +02002975 bacpy(&ev.bdaddr, bdaddr);
Archana Ramachandranda09d262012-08-14 12:03:01 -07002976 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02002977
Szymon Janc4e51eae2011-02-25 19:05:48 +01002978 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002979
2980 if (sk)
2981 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002982
Archana Ramachandranda09d262012-08-14 12:03:01 -07002983 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
2984
Johan Hedberg8962ee72011-01-20 12:40:27 +02002985 return err;
2986}
2987
2988int mgmt_disconnect_failed(u16 index)
2989{
2990 struct pending_cmd *cmd;
2991 int err;
2992
2993 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2994 if (!cmd)
2995 return -ENOENT;
2996
Szymon Janc4e51eae2011-02-25 19:05:48 +01002997 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002998
Johan Hedberga664b5b2011-02-19 12:06:02 -03002999 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000
3001 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003002}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003003
3004int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3005{
3006 struct mgmt_ev_connect_failed ev;
3007
Johan Hedberg17d5c042011-01-22 06:09:08 +02003008 bacpy(&ev.bdaddr, bdaddr);
3009 ev.status = status;
3010
Szymon Janc4e51eae2011-02-25 19:05:48 +01003011 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003012}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003015{
3016 struct mgmt_ev_pin_code_request ev;
3017
Brian Gixa68668b2011-08-11 15:49:36 -07003018 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003019
Johan Hedberg980e1a52011-01-22 06:10:07 +02003020 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003021 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003022
Szymon Janc4e51eae2011-02-25 19:05:48 +01003023 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
3024 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003025}
3026
3027int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3028{
3029 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003030 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003031 int err;
3032
3033 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
3034 if (!cmd)
3035 return -ENOENT;
3036
Johan Hedbergac56fb12011-02-19 12:05:59 -03003037 bacpy(&rp.bdaddr, bdaddr);
3038 rp.status = status;
3039
Szymon Janc4e51eae2011-02-25 19:05:48 +01003040 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
3041 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003042
Johan Hedberga664b5b2011-02-19 12:06:02 -03003043 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003044
3045 return err;
3046}
3047
3048int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3049{
3050 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003051 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003052 int err;
3053
3054 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
3055 if (!cmd)
3056 return -ENOENT;
3057
Johan Hedbergac56fb12011-02-19 12:05:59 -03003058 bacpy(&rp.bdaddr, bdaddr);
3059 rp.status = status;
3060
Szymon Janc4e51eae2011-02-25 19:05:48 +01003061 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
3062 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063
Johan Hedberga664b5b2011-02-19 12:06:02 -03003064 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003065
3066 return err;
3067}
Johan Hedberga5c29682011-02-19 12:05:57 -03003068
Brian Gixa68668b2011-08-11 15:49:36 -07003069int mgmt_user_confirm_request(u16 index, u8 event,
3070 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03003071{
3072 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07003073 struct hci_conn *conn = NULL;
3074 struct hci_dev *hdev;
3075 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03003076
Brian Gixa68668b2011-08-11 15:49:36 -07003077 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03003078
Brian Gixa68668b2011-08-11 15:49:36 -07003079 hdev = hci_dev_get(index);
3080
Brian Gix64bd5302011-09-08 11:35:48 -07003081 if (!hdev)
3082 return -ENODEV;
3083
Brian Gix64bd5302011-09-08 11:35:48 -07003084 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003085
3086 ev.auto_confirm = 0;
3087
3088 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
3089 goto no_auto_confirm;
3090
3091 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
3092 rem_cap = conn->remote_cap;
3093 loc_mitm = conn->auth_type & 0x01;
3094 rem_mitm = conn->remote_auth & 0x01;
3095
Brian Gixdbf59292011-11-11 15:45:17 -08003096 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
3097 conn->auth_initiator && rem_cap == 0x03)
3098 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303099 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
3100 if (!loc_mitm && !rem_mitm)
3101 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07003102 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303103 }
Brian Gixa68668b2011-08-11 15:49:36 -07003104
Bhasker Netif8fffe82012-10-25 17:42:12 +05303105 /* Show bonding dialog if neither side requires no bonding */
3106 if ((conn->auth_type > 0x01) && (conn->remote_auth > 0x01)) {
3107 if (!loc_mitm && !rem_mitm)
3108 value = 0;
3109 goto no_auto_confirm;
3110 }
Brian Gixa68668b2011-08-11 15:49:36 -07003111
3112 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
3113 ev.auto_confirm = 1;
3114
3115no_auto_confirm:
3116 bacpy(&ev.bdaddr, bdaddr);
3117 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03003118 put_unaligned_le32(value, &ev.value);
3119
Brian Gix64bd5302011-09-08 11:35:48 -07003120 hci_dev_put(hdev);
3121
Brian Gixa68668b2011-08-11 15:49:36 -07003122 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
3123 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003124}
3125
Brian Gixa68668b2011-08-11 15:49:36 -07003126int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08003127{
3128 struct mgmt_ev_user_passkey_request ev;
3129
Johan Hedberga5c29682011-02-19 12:05:57 -03003130 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08003131
Johan Hedberga5c29682011-02-19 12:05:57 -03003132 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003133
Brian Gixa68668b2011-08-11 15:49:36 -07003134 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03003135 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003136}
3137
Johan Hedberga5c29682011-02-19 12:05:57 -03003138static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
3139 u8 opcode)
3140{
3141 struct pending_cmd *cmd;
3142 struct mgmt_rp_user_confirm_reply rp;
3143 int err;
3144
3145 cmd = mgmt_pending_find(opcode, index);
3146 if (!cmd)
3147 return -ENOENT;
3148
Johan Hedberga5c29682011-02-19 12:05:57 -03003149 bacpy(&rp.bdaddr, bdaddr);
3150 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003151 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003152
Johan Hedberga664b5b2011-02-19 12:06:02 -03003153 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003154
3155 return err;
3156}
3157
3158int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3159{
3160 return confirm_reply_complete(index, bdaddr, status,
3161 MGMT_OP_USER_CONFIRM_REPLY);
3162}
3163
Szymon Jancb8534e0f2011-03-01 16:55:34 +01003164int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003165{
3166 return confirm_reply_complete(index, bdaddr, status,
3167 MGMT_OP_USER_CONFIRM_NEG_REPLY);
3168}
Johan Hedberg2a611692011-02-19 12:06:00 -03003169
3170int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3171{
3172 struct mgmt_ev_auth_failed ev;
3173
Johan Hedberg2a611692011-02-19 12:06:00 -03003174 bacpy(&ev.bdaddr, bdaddr);
3175 ev.status = status;
3176
Szymon Janc4e51eae2011-02-25 19:05:48 +01003177 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003178}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003179
3180int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
3181{
3182 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003183 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003184 struct mgmt_cp_set_local_name ev;
3185 int err;
3186
3187 memset(&ev, 0, sizeof(ev));
3188 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3189
3190 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
3191 if (!cmd)
3192 goto send_event;
3193
3194 if (status) {
3195 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
3196 goto failed;
3197 }
3198
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003199 hdev = hci_dev_get(index);
3200 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003201 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003202 hci_dev_put(hdev);
3203 }
3204
Johan Hedbergb312b1612011-03-16 14:29:37 +02003205 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
3206 sizeof(ev));
3207 if (err < 0)
3208 goto failed;
3209
3210send_event:
3211 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
3212 cmd ? cmd->sk : NULL);
3213
3214failed:
3215 if (cmd)
3216 mgmt_pending_remove(cmd);
3217 return err;
3218}
Szymon Jancc35938b2011-03-22 13:12:21 +01003219
3220int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
3221 u8 status)
3222{
3223 struct pending_cmd *cmd;
3224 int err;
3225
3226 BT_DBG("hci%u status %u", index, status);
3227
3228 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
3229 if (!cmd)
3230 return -ENOENT;
3231
3232 if (status) {
3233 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3234 EIO);
3235 } else {
3236 struct mgmt_rp_read_local_oob_data rp;
3237
3238 memcpy(rp.hash, hash, sizeof(rp.hash));
3239 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3240
3241 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3242 &rp, sizeof(rp));
3243 }
3244
3245 mgmt_pending_remove(cmd);
3246
3247 return err;
3248}
Johan Hedberge17acd42011-03-30 23:57:16 +03003249
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003250void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
3251 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02003252{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003253 struct mgmt_ev_rssi_update ev;
3254 struct hci_conn *conn;
3255 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003256
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003257 if (status)
3258 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003259
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003260 hdev = hci_dev_get(index);
3261 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003262
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003263 if (!conn)
3264 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003265
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003266 BT_DBG("rssi_update_thresh_exceed : %d ",
3267 conn->rssi_update_thresh_exceed);
3268 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
3269 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003270
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003271 if (conn->rssi_update_thresh_exceed == 1) {
3272 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003273 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003274 memset(&ev, 0, sizeof(ev));
3275 bacpy(&ev.bdaddr, bdaddr);
3276 ev.rssi = rssi;
3277 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3278 sizeof(ev), NULL);
3279 } else {
3280 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3281 conn->rssi_update_interval,
3282 conn->rssi_update_thresh_exceed);
3283 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003284 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003285 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003286 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003287 memset(&ev, 0, sizeof(ev));
3288 bacpy(&ev.bdaddr, bdaddr);
3289 ev.rssi = rssi;
3290 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3291 sizeof(ev), NULL);
3292 } else {
3293 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3294 conn->rssi_update_interval,
3295 conn->rssi_update_thresh_exceed);
3296 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003297 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003298}
3299
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003300
Brian Gixa68668b2011-08-11 15:49:36 -07003301int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
3302 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03003303{
3304 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08003305 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003306 int err;
3307
Brian Gixa68668b2011-08-11 15:49:36 -07003308 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003309
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003310 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003311
Johan Hedberge17acd42011-03-30 23:57:16 +03003312 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03003313 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07003314 ev.type = type;
3315 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03003316
Brian Gixa68668b2011-08-11 15:49:36 -07003317 if (dev_class)
3318 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03003319
Brian Gixa68668b2011-08-11 15:49:36 -07003320 if (eir && eir_len)
3321 memcpy(ev.eir, eir, eir_len);
3322
3323 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3324
3325 if (err < 0)
3326 return err;
3327
Brian Gix568dde92012-01-11 16:18:04 -08003328 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003329
Brian Gix568dde92012-01-11 16:18:04 -08003330 if (!hdev)
3331 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003332
Brian Gix568dde92012-01-11 16:18:04 -08003333 if (hdev->disco_state == SCAN_IDLE)
3334 goto done;
3335
3336 hdev->disco_int_count++;
3337
3338 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3339 /* Inquiry scan for General Discovery LAP */
3340 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3341 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3342
3343 hdev->disco_int_phase *= 2;
3344 hdev->disco_int_count = 0;
3345 if (hdev->disco_state == SCAN_LE) {
3346 /* cancel LE scan */
3347 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3348 sizeof(le_cp), &le_cp);
3349 /* start BR scan */
3350 cp.num_rsp = (u8) hdev->disco_int_phase;
3351 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3352 sizeof(cp), &cp);
3353 hdev->disco_state = SCAN_BR;
3354 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003355 }
3356 }
3357
Brian Gix568dde92012-01-11 16:18:04 -08003358done:
3359 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003360 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003361}
Antti Julku5e762442011-08-25 16:48:02 +03003362
Brian Gixa68668b2011-08-11 15:49:36 -07003363
3364int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003365{
Johan Hedberga88a9652011-03-30 13:18:12 +03003366 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003367
Johan Hedberga88a9652011-03-30 13:18:12 +03003368 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003369
Johan Hedberga88a9652011-03-30 13:18:12 +03003370 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003371 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003372 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003373
Johan Hedberga88a9652011-03-30 13:18:12 +03003374 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003375}
3376
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303377int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003378{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303379 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003380
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303381 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003382
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303383 bacpy(&ev.bdaddr, bdaddr);
3384 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003385
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303386 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3387 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003388}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003389
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303390int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3391{
3392 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003393
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303394 memset(&ev, 0, sizeof(ev));
3395
3396 bacpy(&ev.bdaddr, bdaddr);
3397 memcpy(ev.dev_class, dev_class, 3);
3398
3399 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3400}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303401
3402int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3403 u16 sub_ver)
3404{
3405 struct mgmt_ev_remote_version ev;
3406
3407 memset(&ev, 0, sizeof(ev));
3408
3409 bacpy(&ev.bdaddr, bdaddr);
3410 ev.lmp_ver = ver;
3411 ev.manufacturer = mnf;
3412 ev.lmp_subver = sub_ver;
3413
3414 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3415}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003416
3417int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3418{
3419 struct mgmt_ev_remote_features ev;
3420
3421 memset(&ev, 0, sizeof(ev));
3422
3423 bacpy(&ev.bdaddr, bdaddr);
3424 memcpy(ev.features, features, sizeof(ev.features));
3425
3426 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3427 NULL);
3428}