blob: a1f2955cd1cc63eb575cea1f91211365f175cdf0 [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 }
386
387 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
388 if (!cmd) {
389 err = -ENOMEM;
390 goto failed;
391 }
392
Bhasker Neti86a4b322012-10-29 15:22:33 +0530393 hci_dev_unlock_bh(hdev);
394
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200395 if (cp->val)
396 queue_work(hdev->workqueue, &hdev->power_on);
397 else
398 queue_work(hdev->workqueue, &hdev->power_off);
399
400 err = 0;
Bhasker Neti86a4b322012-10-29 15:22:33 +0530401 hci_dev_put(hdev);
402
403 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200404
405failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800406 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200407 hci_dev_put(hdev);
408 return err;
409}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200410
Brian Gix8a7f1642011-10-17 17:39:46 -0700411static u8 get_service_classes(struct hci_dev *hdev)
412{
413 struct list_head *p;
414 u8 val = 0;
415
416 list_for_each(p, &hdev->uuids) {
417 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
418
419 val |= uuid->svc_hint;
420 }
421
422 return val;
423}
424
425static int update_class(struct hci_dev *hdev)
426{
427 u8 cod[3];
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530428 int err = 0;
Brian Gix8a7f1642011-10-17 17:39:46 -0700429
430 BT_DBG("%s", hdev->name);
431
432 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
433 return 0;
434
435 cod[0] = hdev->minor_class;
436 cod[1] = hdev->major_class;
437 cod[2] = get_service_classes(hdev);
438
439 if (memcmp(cod, hdev->dev_class, 3) == 0)
440 return 0;
441
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530442 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
443
444 if (err == 0)
445 memcpy(hdev->dev_class, cod, 3);
446
447 return err;
Brian Gix8a7f1642011-10-17 17:39:46 -0700448}
449
450static int set_limited_discoverable(struct sock *sk, u16 index,
451 unsigned char *data, u16 len)
452{
453 struct mgmt_mode *cp;
454 struct hci_dev *hdev;
455 struct pending_cmd *cmd;
456 struct hci_cp_write_current_iac_lap dcp;
457 int update_cod;
458 int err = 0;
459 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
460 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
461
462 cp = (void *) data;
463
464 BT_DBG("hci%u discoverable: %d", index, cp->val);
465
466 if (!cp || len != sizeof(*cp))
467 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
468 EINVAL);
469
470 hdev = hci_dev_get(index);
471 if (!hdev)
472 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
473 ENODEV);
474
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800475 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700476
477 if (!test_bit(HCI_UP, &hdev->flags)) {
478 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
479 ENETDOWN);
480 goto failed;
481 }
482
483 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
484 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
485 EBUSY);
486 goto failed;
487 }
488
489 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
490 test_bit(HCI_PSCAN, &hdev->flags)) {
491 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
492 EALREADY);
493 goto failed;
494 }
495
496 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
497 len);
498 if (!cmd) {
499 err = -ENOMEM;
500 goto failed;
501 }
502
503 memset(&dcp, 0, sizeof(dcp));
504 dcp.num_current_iac = cp->val ? 2 : 1;
505 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
506 update_cod = 1;
507
508 if (cp->val) {
509 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
510 update_cod = 0;
511 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
512 } else {
513 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
514 update_cod = 0;
515 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
516 }
517
518 if (update_cod)
519 err = update_class(hdev);
520
521 if (err >= 0)
522 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
523 sizeof(dcp), &dcp);
524
525 if (err < 0)
526 mgmt_pending_remove(cmd);
527
528failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800529 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700530 hci_dev_put(hdev);
531
532 return err;
533}
534
Johan Hedberg73f22f62010-12-29 16:00:25 +0200535static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
536 u16 len)
537{
538 struct mgmt_mode *cp;
539 struct hci_dev *hdev;
540 struct pending_cmd *cmd;
541 u8 scan;
542 int err;
543
544 cp = (void *) data;
545
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200546 BT_DBG("request for hci%u", index);
547
Johan Hedberg72a734e2010-12-30 00:38:22 +0200548 if (len != sizeof(*cp))
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200549 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
550
551 hdev = hci_dev_get(index);
552 if (!hdev)
553 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
554
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800555 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200556
557 if (!test_bit(HCI_UP, &hdev->flags)) {
558 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
559 goto failed;
560 }
561
562 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
563 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
564 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200565 goto failed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200566 }
567
568 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
569 test_bit(HCI_PSCAN, &hdev->flags)) {
570 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
571 goto failed;
572 }
573
574 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
575 if (!cmd) {
576 err = -ENOMEM;
577 goto failed;
578 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200579
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200580 scan = SCAN_PAGE;
581
582 if (cp->val)
583 scan |= SCAN_INQUIRY;
584
585 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
586 if (err < 0)
587 mgmt_pending_remove(cmd);
588
589failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800590 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200591 hci_dev_put(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200592
593 return err;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200594}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200595
596static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
597 u16 len)
598{
599 struct mgmt_mode *cp;
600 struct hci_dev *hdev;
601 struct pending_cmd *cmd;
602 u8 scan;
603 int err;
604
605 cp = (void *) data;
606
607 BT_DBG("request for hci%u", index);
608
609 if (len != sizeof(*cp))
610 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
611
612 hdev = hci_dev_get(index);
613 if (!hdev)
614 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
615
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800616 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200617
Johan Hedberg73f22f62010-12-29 16:00:25 +0200618 if (!test_bit(HCI_UP, &hdev->flags)) {
619 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
620 goto failed;
621 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200622
Johan Hedberg73f22f62010-12-29 16:00:25 +0200623 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
624 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
625 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
626 goto failed;
627 }
628
629 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
630 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
631 goto failed;
632 }
633
Johan Hedberg72a734e2010-12-30 00:38:22 +0200634 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200635 if (!cmd) {
636 err = -ENOMEM;
637 goto failed;
638 }
639
640 if (cp->val)
641 scan = SCAN_PAGE;
642 else
643 scan = 0;
644
645 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
646 if (err < 0)
647 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200648
649failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800650 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200651 hci_dev_put(hdev);
652
653 return err;
654}
655
656static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
657 struct sock *skip_sk)
658{
659 struct sk_buff *skb;
660 struct mgmt_hdr *hdr;
661
Brian Gixa68668b2011-08-11 15:49:36 -0700662 BT_DBG("hci%d %d", index, event);
663
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200664 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
665 if (!skb)
666 return -ENOMEM;
667
668 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
669
670 hdr = (void *) skb_put(skb, sizeof(*hdr));
671 hdr->opcode = cpu_to_le16(event);
672 hdr->index = cpu_to_le16(index);
673 hdr->len = cpu_to_le16(data_len);
674
675 if (data)
676 memcpy(skb_put(skb, data_len), data, data_len);
677
678 hci_send_to_sock(NULL, skb, skip_sk);
679 kfree_skb(skb);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200680
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200681 return 0;
682}
683
684static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
685{
686 struct mgmt_mode rp;
687
688 rp.val = val;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200689
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200690 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
691}
692
693static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
694 u16 len)
695{
696 struct mgmt_mode *cp, ev;
697 struct hci_dev *hdev;
698 int err;
699
700 cp = (void *) data;
701
702 BT_DBG("request for hci%u", index);
703
704 if (len != sizeof(*cp))
Johan Hedberg053f0212011-01-26 13:07:10 +0200705 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
706
707 hdev = hci_dev_get(index);
708 if (!hdev)
709 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
710
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800711 hci_dev_lock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200712
713 if (cp->val)
714 set_bit(HCI_PAIRABLE, &hdev->flags);
715 else
716 clear_bit(HCI_PAIRABLE, &hdev->flags);
717
718 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
719 if (err < 0)
720 goto failed;
721
722 ev.val = cp->val;
723
724 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
725
726failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800727 hci_dev_unlock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200728 hci_dev_put(hdev);
729
730 return err;
731}
732
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300733#define EIR_FLAGS 0x01 /* flags */
734#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
735#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
736#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
737#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
738#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
739#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
740#define EIR_NAME_SHORT 0x08 /* shortened local name */
741#define EIR_NAME_COMPLETE 0x09 /* complete local name */
742#define EIR_TX_POWER 0x0A /* transmit power level */
743#define EIR_DEVICE_ID 0x10 /* device ID */
744
745#define PNP_INFO_SVCLASS_ID 0x1200
746
747static u8 bluetooth_base_uuid[] = {
748 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
749 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750};
751
752static u16 get_uuid16(u8 *uuid128)
753{
754 u32 val;
755 int i;
756
757 for (i = 0; i < 12; i++) {
758 if (bluetooth_base_uuid[i] != uuid128[i])
759 return 0;
760 }
761
762 memcpy(&val, &uuid128[12], 4);
763
764 val = le32_to_cpu(val);
765 if (val > 0xffff)
766 return 0;
767
768 return (u16) val;
769}
770
771static void create_eir(struct hci_dev *hdev, u8 *data)
772{
773 u8 *ptr = data;
774 u16 eir_len = 0;
775 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
776 int i, truncated = 0;
777 struct list_head *p;
778 size_t name_len;
779
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530780 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300781
782 if (name_len > 0) {
783 /* EIR Data type */
784 if (name_len > 48) {
785 name_len = 48;
786 ptr[1] = EIR_NAME_SHORT;
787 } else
788 ptr[1] = EIR_NAME_COMPLETE;
789
790 /* EIR Data length */
791 ptr[0] = name_len + 1;
792
793 memcpy(ptr + 2, hdev->dev_name, name_len);
794
795 eir_len += (name_len + 2);
796 ptr += (name_len + 2);
797 }
798
799 memset(uuid16_list, 0, sizeof(uuid16_list));
800
801 /* Group all UUID16 types */
802 list_for_each(p, &hdev->uuids) {
803 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
804 u16 uuid16;
805
806 uuid16 = get_uuid16(uuid->uuid);
807 if (uuid16 == 0)
808 return;
809
810 if (uuid16 < 0x1100)
811 continue;
812
813 if (uuid16 == PNP_INFO_SVCLASS_ID)
814 continue;
815
816 /* Stop if not enough space to put next UUID */
817 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
818 truncated = 1;
819 break;
820 }
821
822 /* Check for duplicates */
823 for (i = 0; uuid16_list[i] != 0; i++)
824 if (uuid16_list[i] == uuid16)
825 break;
826
827 if (uuid16_list[i] == 0) {
828 uuid16_list[i] = uuid16;
829 eir_len += sizeof(u16);
830 }
831 }
832
833 if (uuid16_list[0] != 0) {
834 u8 *length = ptr;
835
836 /* EIR Data type */
837 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
838
839 ptr += 2;
840 eir_len += 2;
841
842 for (i = 0; uuid16_list[i] != 0; i++) {
843 *ptr++ = (uuid16_list[i] & 0x00ff);
844 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
845 }
846
847 /* EIR Data length */
848 *length = (i * sizeof(u16)) + 1;
849 }
850}
851
852static int update_eir(struct hci_dev *hdev)
853{
854 struct hci_cp_write_eir cp;
855
856 if (!(hdev->features[6] & LMP_EXT_INQ))
857 return 0;
858
859 if (hdev->ssp_mode == 0)
860 return 0;
861
862 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
863 return 0;
864
865 memset(&cp, 0, sizeof(cp));
866
867 create_eir(hdev, cp.data);
868
869 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
870 return 0;
871
872 memcpy(hdev->eir, cp.data, sizeof(cp.data));
873
874 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
875}
876
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200879 struct mgmt_cp_add_uuid *cp;
880 struct hci_dev *hdev;
881 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200882 int err;
883
884 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200885
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200886 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200888 if (len != sizeof(*cp))
889 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
890
891 hdev = hci_dev_get(index);
892 if (!hdev)
893 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
894
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800895 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200896
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200897 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
898 if (!uuid) {
899 err = -ENOMEM;
900 goto failed;
901 }
902
903 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200905
906 list_add(&uuid->list, &hdev->uuids);
907
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530908 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200909
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530910 err = update_class(hdev);
911 if (err < 0)
912 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300913
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530914 err = update_eir(hdev);
915 if (err < 0)
916 goto failed;
917 } else
918 err = 0;
Johan Hedberg90e70452012-02-23 23:09:40 +0200919
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200921
922failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800923 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924 hci_dev_put(hdev);
925
926 return err;
927}
928
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg24b78d02012-02-23 23:24:30 +0200930{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200931 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100932 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200933 struct hci_dev *hdev;
934 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 +0200935 int err, found;
936
937 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200938
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200939 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200940
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200941 if (len != sizeof(*cp))
942 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
943
944 hdev = hci_dev_get(index);
945 if (!hdev)
946 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
947
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800948 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200949
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200950 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
951 err = hci_uuids_clear(hdev);
952 goto unlock;
953 }
954
955 found = 0;
956
957 list_for_each_safe(p, n, &hdev->uuids) {
958 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
959
960 if (memcmp(match->uuid, cp->uuid, 16) != 0)
961 continue;
962
963 list_del(&match->list);
964 found++;
965 }
966
967 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100968 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200969 goto unlock;
970 }
971
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530972 if (test_bit(HCI_UP, &hdev->flags)) {
973 err = update_class(hdev);
974 if (err < 0)
975 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200976
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530977 err = update_eir(hdev);
978 if (err < 0)
979 goto unlock;
980 } else
981 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300982
Szymon Janc4e51eae2011-02-25 19:05:48 +0100983 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200984
985unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800986 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200987 hci_dev_put(hdev);
988
989 return err;
990}
991
Szymon Janc4e51eae2011-02-25 19:05:48 +0100992static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
993 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994{
995 struct hci_dev *hdev;
996 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200997 int err;
998
999 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001001 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001003 if (len != sizeof(*cp))
1004 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001005
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006 hdev = hci_dev_get(index);
1007 if (!hdev)
1008 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
1009
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001010 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001011
Brian Gix8a7f1642011-10-17 17:39:46 -07001012 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1013 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001014 hdev->minor_class = cp->minor;
1015
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301016 if (test_bit(HCI_UP, &hdev->flags)) {
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301017 err = update_class(hdev);
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301018 if (err == 0)
1019 err = cmd_complete(sk, index,
1020 MGMT_OP_SET_DEV_CLASS, hdev->dev_class, sizeof(u8)*3);
1021 } else
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001023
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001024 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001025 hci_dev_put(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001026
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001027 return err;
1028}
1029
Johan Hedberg03811012010-12-08 00:21:06 +02001030static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1031 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001032{
Johan Hedberg03811012010-12-08 00:21:06 +02001033 struct hci_dev *hdev;
1034 struct mgmt_cp_set_service_cache *cp;
1035 int err;
1036
1037 cp = (void *) data;
1038
1039 if (len != sizeof(*cp))
1040 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
1041
1042 hdev = hci_dev_get(index);
1043 if (!hdev)
1044 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1045
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001046 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001047
1048 BT_DBG("hci%u enable %d", index, cp->enable);
1049
1050 if (cp->enable) {
1051 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1052 err = 0;
1053 } else {
1054 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301055 if (test_bit(HCI_UP, &hdev->flags)) {
1056 err = update_class(hdev);
1057 if (err == 0)
1058 err = update_eir(hdev);
1059 } else
1060 err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02001061 }
1062
1063 if (err == 0)
1064 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1065 0);
1066
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001067 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001068 hci_dev_put(hdev);
1069
1070 return err;
1071}
1072
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001073static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
1074{
1075 struct hci_dev *hdev;
1076 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001077 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001078 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001079
1080 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001081
1082 if (len < sizeof(*cp))
1083 return -EINVAL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001084
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001085 key_count = get_unaligned_le16(&cp->key_count);
1086
1087 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001088 if (expected_len > len) {
1089 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1090 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001091 return -EINVAL;
1092 }
1093
Szymon Janc4e51eae2011-02-25 19:05:48 +01001094 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001095 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001096 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001097
Szymon Janc4e51eae2011-02-25 19:05:48 +01001098 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001099 key_count);
1100
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001101 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001102
1103 hci_link_keys_clear(hdev);
1104
1105 set_bit(HCI_LINK_KEYS, &hdev->flags);
1106
1107 if (cp->debug_keys)
1108 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1109 else
1110 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1111
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001112 len -= sizeof(*cp);
1113 i = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001114
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001115 while (i < len) {
1116 struct mgmt_key_info *key = (void *) cp->keys + i;
1117
Brian Gixa68668b2011-08-11 15:49:36 -07001118 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001119
Brian Gixcf956772011-10-20 15:18:51 -07001120 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001121 struct key_master_id *id = (void *) key->data;
1122
1123 if (key->dlen != sizeof(struct key_master_id))
1124 continue;
1125
Brian Gixcf956772011-10-20 15:18:51 -07001126 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1127 key->pin_len, key->auth, id->ediv,
1128 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001129
1130 continue;
1131 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001132
Brian Gixcf956772011-10-20 15:18:51 -07001133 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001134 key->pin_len);
1135 }
1136
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001137 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001138
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001139 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001140 hci_dev_put(hdev);
1141
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001142 return err;
1143}
1144
Johan Hedberg03811012010-12-08 00:21:06 +02001145static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001146{
Johan Hedberg03811012010-12-08 00:21:06 +02001147 struct hci_dev *hdev;
1148 struct mgmt_cp_remove_key *cp;
1149 struct hci_conn *conn;
1150 int err;
1151
1152 cp = (void *) data;
1153
1154 if (len != sizeof(*cp))
1155 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1156
1157 hdev = hci_dev_get(index);
1158 if (!hdev)
1159 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
1160
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001161 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001162
1163 err = hci_remove_link_key(hdev, &cp->bdaddr);
1164 if (err < 0) {
1165 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
1166 goto unlock;
1167 }
1168
1169 err = 0;
1170
1171 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1172 goto unlock;
1173
1174 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1175 if (conn) {
1176 struct hci_cp_disconnect dc;
1177
1178 put_unaligned_le16(conn->handle, &dc.handle);
1179 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02001181 }
1182
1183unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001184 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001185 hci_dev_put(hdev);
1186
1187 return err;
1188}
1189
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
1191{
1192 struct hci_dev *hdev;
1193 struct mgmt_cp_disconnect *cp;
1194 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001195 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197 int err;
1198
1199 BT_DBG("");
1200
1201 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001202
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001203 if (len != sizeof(*cp))
1204 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1205
Szymon Janc4e51eae2011-02-25 19:05:48 +01001206 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001207 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001208 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001209
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001210 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001211
1212 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001214 goto failed;
1215 }
1216
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1218 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001219 goto failed;
1220 }
1221
1222 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1223 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001224 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1225 if (!conn) {
1226 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1227 ENOTCONN);
1228 goto failed;
1229 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001230 }
1231
Szymon Janc4e51eae2011-02-25 19:05:48 +01001232 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001233 if (!cmd) {
1234 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001235 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001236 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001237
1238 put_unaligned_le16(conn->handle, &dc.handle);
1239 dc.reason = 0x13; /* Remote User Terminated Connection */
1240
1241 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1242 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001243 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001244
1245failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001246 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001247 hci_dev_put(hdev);
1248
1249 return err;
1250}
1251
Szymon Janc8ce62842011-03-01 16:55:32 +01001252static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001254 struct mgmt_rp_get_connections *rp;
1255 struct hci_dev *hdev;
1256 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001257 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001258 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259 int i, err;
1260
1261 BT_DBG("");
1262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001267 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268
1269 count = 0;
1270 list_for_each(p, &hdev->conn_hash.list) {
1271 count++;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001272 }
1273
Johan Hedberga38528f2011-01-22 06:46:43 +02001274 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1275 rp = kmalloc(rp_len, GFP_ATOMIC);
1276 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001277 err = -ENOMEM;
1278 goto unlock;
1279 }
1280
Johan Hedberg2784eb42011-01-21 13:56:35 +02001281 put_unaligned_le16(count, &rp->conn_count);
1282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 read_lock(&hci_dev_list_lock);
1284
Johan Hedberg2784eb42011-01-21 13:56:35 +02001285 i = 0;
1286 list_for_each(p, &hdev->conn_hash.list) {
1287 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1288
1289 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001290 }
1291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 read_unlock(&hci_dev_list_lock);
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001293
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001295
1296unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001297 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001298 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001299 hci_dev_put(hdev);
1300 return err;
1301}
1302
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1304 u16 len)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001305{
Johan Hedberg980e1a52011-01-22 06:10:07 +02001306 struct hci_dev *hdev;
1307 struct mgmt_cp_pin_code_reply *cp;
1308 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001309 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001310 int err;
1311
1312 BT_DBG("");
1313
1314 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315
Johan Hedberg980e1a52011-01-22 06:10:07 +02001316 if (len != sizeof(*cp))
1317 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1318
1319 hdev = hci_dev_get(index);
1320 if (!hdev)
1321 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
1322
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001323 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324
1325 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001327 goto failed;
1328 }
1329
Szymon Janc4e51eae2011-02-25 19:05:48 +01001330 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001331 if (!cmd) {
1332 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001333 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001334 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001335
1336 bacpy(&reply.bdaddr, &cp->bdaddr);
1337 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339
1340 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1341 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001342 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001343
1344failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001345 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346 hci_dev_put(hdev);
1347
1348 return err;
1349}
1350
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301351static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1352 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001353{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301354 struct hci_dev *hdev;
1355 struct mgmt_cp_encrypt_link *cp;
1356 struct hci_cp_set_conn_encrypt enc;
1357 struct hci_conn *conn;
1358 int err = 0;
1359
1360 BT_DBG("");
1361
1362 cp = (void *) data;
1363
1364 if (len != sizeof(*cp))
1365 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1366
1367 hdev = hci_dev_get(index);
1368 if (!hdev)
1369 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1370
Brian Gix384ec672012-03-08 18:41:15 -08001371 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301372
1373 if (!test_bit(HCI_UP, &hdev->flags)) {
1374 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001375 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301376 }
1377
Brian Gix384ec672012-03-08 18:41:15 -08001378 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1379 if (!conn) {
1380 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1381 goto done;
1382 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301383
Brian Gix384ec672012-03-08 18:41:15 -08001384 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1385 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1386 goto done;
1387 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301388
1389 if (conn->link_mode & HCI_LM_AUTH) {
1390 enc.handle = cpu_to_le16(conn->handle);
1391 enc.encrypt = cp->enable;
1392 err = hci_send_cmd(hdev,
1393 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1394 } else {
1395 conn->auth_initiator = 1;
1396 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1397 struct hci_cp_auth_requested cp;
1398 cp.handle = cpu_to_le16(conn->handle);
1399 err = hci_send_cmd(conn->hdev,
1400 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1401 }
1402 }
1403
Brian Gix384ec672012-03-08 18:41:15 -08001404done:
1405 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301406 hci_dev_put(hdev);
1407
1408 return err;
1409}
1410
1411
Johan Hedberg980e1a52011-01-22 06:10:07 +02001412static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1413 u16 len)
1414{
1415 struct hci_dev *hdev;
1416 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001418 int err;
1419
1420 BT_DBG("");
1421
1422 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423
Johan Hedberg980e1a52011-01-22 06:10:07 +02001424 if (len != sizeof(*cp))
1425 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1426 EINVAL);
1427
1428 hdev = hci_dev_get(index);
1429 if (!hdev)
1430 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1431 ENODEV);
1432
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001433 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001434
1435 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1437 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001438 goto failed;
1439 }
1440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1442 data, len);
1443 if (!cmd) {
1444 err = -ENOMEM;
1445 goto failed;
1446 }
1447
1448 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1449 &cp->bdaddr);
1450 if (err < 0)
1451 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001452
1453failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001454 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001455 hci_dev_put(hdev);
1456
1457 return err;
1458}
1459
Sunny Kapdi93bef892012-07-30 14:52:56 -07001460static int le_add_dev_white_list(struct sock *sk, u16 index,
1461 unsigned char *data, u16 len)
1462{
1463 struct hci_dev *hdev;
1464 struct mgmt_cp_le_add_dev_white_list *cp;
1465 int err = 0;
1466
1467 BT_DBG("");
1468
1469 cp = (void *) data;
1470
1471 if (len != sizeof(*cp))
1472 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1473 EINVAL);
1474
1475 hdev = hci_dev_get(index);
1476 if (!hdev)
1477 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1478 ENODEV);
1479
1480 hci_dev_lock_bh(hdev);
1481
1482 if (!test_bit(HCI_UP, &hdev->flags)) {
1483 err = cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1484 ENETDOWN);
1485 goto failed;
1486 }
1487
1488 hci_le_add_dev_white_list(hdev, &cp->bdaddr);
1489
1490failed:
1491 hci_dev_unlock_bh(hdev);
1492 hci_dev_put(hdev);
1493
1494 return err;
1495}
1496
1497static int le_remove_dev_white_list(struct sock *sk, u16 index,
1498 unsigned char *data, u16 len)
1499{
1500 struct hci_dev *hdev;
1501 struct mgmt_cp_le_remove_dev_white_list *cp;
1502 int err = 0;
1503
1504 BT_DBG("");
1505
1506 cp = (void *) data;
1507
1508 if (len != sizeof(*cp))
1509 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1510 EINVAL);
1511
1512 hdev = hci_dev_get(index);
1513 if (!hdev)
1514 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1515 ENODEV);
1516
1517 hci_dev_lock_bh(hdev);
1518
1519 if (!test_bit(HCI_UP, &hdev->flags)) {
1520 err = cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1521 ENETDOWN);
1522 goto failed;
1523 }
1524
1525 hci_le_remove_dev_white_list(hdev, &cp->bdaddr);
1526
1527failed:
1528 hci_dev_unlock_bh(hdev);
1529 hci_dev_put(hdev);
1530
1531 return err;
1532}
1533
1534static int le_create_conn_white_list(struct sock *sk, u16 index)
1535{
1536 struct hci_dev *hdev;
1537 struct hci_conn *conn;
1538 u8 sec_level, auth_type;
1539 struct pending_cmd *cmd;
1540 bdaddr_t bdaddr;
1541 int err = 0;
1542
1543 BT_DBG("");
1544
1545 hdev = hci_dev_get(index);
1546 if (!hdev)
1547 return cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1548 ENODEV);
1549
1550 hci_dev_lock_bh(hdev);
1551
1552 if (!test_bit(HCI_UP, &hdev->flags)) {
1553 err = cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1554 ENETDOWN);
1555 goto failed;
1556 }
1557
1558 cmd = mgmt_pending_add(sk, MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index,
1559 NULL, 0);
1560 if (!cmd) {
1561 err = -ENOMEM;
1562 goto failed;
1563 }
1564
1565 sec_level = BT_SECURITY_MEDIUM;
1566 auth_type = HCI_AT_GENERAL_BONDING;
1567 memset(&bdaddr, 0, sizeof(bdaddr));
1568 conn = hci_le_connect(hdev, 0, BDADDR_ANY, sec_level, auth_type, NULL);
1569 if (IS_ERR(conn)) {
1570 err = PTR_ERR(conn);
1571 mgmt_pending_remove(cmd);
1572 }
1573
1574failed:
1575 hci_dev_unlock_bh(hdev);
1576 hci_dev_put(hdev);
1577
1578 return err;
1579}
1580
1581static int le_cancel_create_conn_white_list(struct sock *sk, u16 index)
1582{
1583 struct hci_dev *hdev;
1584 int err = 0;
1585
1586 BT_DBG("");
1587
1588 hdev = hci_dev_get(index);
1589 if (!hdev)
1590 return cmd_status(sk, index,
1591 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENODEV);
1592
1593 hci_dev_lock_bh(hdev);
1594
1595 if (!test_bit(HCI_UP, &hdev->flags)) {
1596 err = cmd_status(sk, index,
1597 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENETDOWN);
1598 goto failed;
1599 }
1600
1601 hci_le_cancel_create_connect(hdev, BDADDR_ANY);
1602
1603failed:
1604 hci_dev_unlock_bh(hdev);
1605 hci_dev_put(hdev);
1606
1607 return err;
1608}
1609
1610static int le_clear_white_list(struct sock *sk, u16 index)
1611{
1612 struct hci_dev *hdev;
1613 int err;
1614
1615 BT_DBG("");
1616
1617 hdev = hci_dev_get(index);
1618 if (!hdev)
1619 return cmd_status(sk, index,
1620 MGMT_OP_LE_CLEAR_WHITE_LIST, ENODEV);
1621
1622 hci_dev_lock_bh(hdev);
1623
1624 if (!test_bit(HCI_UP, &hdev->flags)) {
1625 err = cmd_status(sk, index,
1626 MGMT_OP_LE_CLEAR_WHITE_LIST, ENETDOWN);
1627 goto failed;
1628 }
1629
1630 err = hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
1631
1632failed:
1633 hci_dev_unlock_bh(hdev);
1634 hci_dev_put(hdev);
1635
1636 return err;
1637}
1638
Szymon Janc4e51eae2011-02-25 19:05:48 +01001639static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1640 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001641{
1642 struct hci_dev *hdev;
1643 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001644
1645 BT_DBG("");
1646
1647 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001648
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001649 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001650 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001651
Szymon Janc4e51eae2011-02-25 19:05:48 +01001652 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001653 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001654 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001655
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001656 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001657
1658 hdev->io_capability = cp->io_capability;
1659
1660 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001661 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001662
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001663 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001664 hci_dev_put(hdev);
1665
Szymon Janc4e51eae2011-02-25 19:05:48 +01001666 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001667}
1668
Johan Hedberge9a416b2011-02-19 12:05:56 -03001669static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1670{
1671 struct hci_dev *hdev = conn->hdev;
1672 struct list_head *p;
1673
1674 list_for_each(p, &cmd_list) {
1675 struct pending_cmd *cmd;
1676
1677 cmd = list_entry(p, struct pending_cmd, list);
1678
1679 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1680 continue;
1681
1682 if (cmd->index != hdev->id)
1683 continue;
1684
1685 if (cmd->user_data != conn)
1686 continue;
1687
1688 return cmd;
1689 }
1690
1691 return NULL;
1692}
1693
1694static void pairing_complete(struct pending_cmd *cmd, u8 status)
1695{
1696 struct mgmt_rp_pair_device rp;
1697 struct hci_conn *conn = cmd->user_data;
1698
Brian Gixa68668b2011-08-11 15:49:36 -07001699 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001700
Johan Hedberge9a416b2011-02-19 12:05:56 -03001701 bacpy(&rp.bdaddr, &conn->dst);
1702 rp.status = status;
1703
Szymon Janc4e51eae2011-02-25 19:05:48 +01001704 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001705
1706 /* So we don't get further callbacks for this connection */
1707 conn->connect_cfm_cb = NULL;
1708 conn->security_cfm_cb = NULL;
1709 conn->disconn_cfm_cb = NULL;
1710
Johan Hedberga664b5b2011-02-19 12:06:02 -03001711 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001712}
1713
1714static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1715{
1716 struct pending_cmd *cmd;
1717
Brian Gixa68668b2011-08-11 15:49:36 -07001718 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001719
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001720 cmd = find_pairing(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001721 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001722 BT_DBG("Unable to find a pending command");
Johan Hedberge9a416b2011-02-19 12:05:56 -03001723 return;
1724 }
1725
1726 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001727 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001728}
1729
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001730static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001731{
Johan Hedberge9a416b2011-02-19 12:05:56 -03001732 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001733
1734 BT_DBG(" %u", status);
1735
1736 cmd = find_pairing(conn);
1737 if (!cmd) {
1738 BT_DBG("Unable to find a pending command");
1739 return;
1740 }
1741
1742 if (conn->type == LE_LINK)
1743 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1744 status ? 0 : 1);
1745 else
1746 pairing_complete(cmd, status);
1747}
1748
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001749static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001750{
1751 struct pending_cmd *cmd;
1752
1753 BT_DBG("conn: %p %u", conn, status);
1754
1755 cmd = find_pairing(conn);
1756 if (!cmd) {
1757 BT_DBG("Unable to find a pending command");
1758 return;
1759 }
Brian Gix114f3a62011-09-27 14:02:20 -07001760
Srinivas Krovvidi52b05ba2012-08-27 18:32:45 +05301761 if (status || conn->pending_sec_level < BT_SECURITY_MEDIUM)
Brian Gix114f3a62011-09-27 14:02:20 -07001762 pairing_complete(cmd, status);
1763
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001764 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001765}
1766
1767static void discovery_terminated(struct pending_cmd *cmd, void *data)
1768{
Brian Gix6e349d02011-11-28 14:51:14 -08001769 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001770 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001771
1772 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001773 hdev = hci_dev_get(cmd->index);
1774 if (!hdev)
1775 goto not_found;
1776
Brian Gix568dde92012-01-11 16:18:04 -08001777 del_timer(&hdev->disco_le_timer);
1778 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001779 hci_dev_put(hdev);
1780
1781not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001782 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1783
1784 list_del(&cmd->list);
1785
1786 mgmt_pending_free(cmd);
1787}
1788
Johan Hedberge9a416b2011-02-19 12:05:56 -03001789static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
1790{
1791 struct hci_dev *hdev;
1792 struct mgmt_cp_pair_device *cp;
1793 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001794 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001795 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001796 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001797 int err;
1798
1799 BT_DBG("");
1800
Brian Gix64bd5302011-09-08 11:35:48 -07001801 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001802
Brian Gix64bd5302011-09-08 11:35:48 -07001803 if (len != sizeof(*cp))
1804 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1805
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001807
Johan Hedberge9a416b2011-02-19 12:05:56 -03001808 if (!hdev)
1809 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
1810
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001811 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301813 io_cap = cp->io_cap;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001814
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001815 sec_level = BT_SECURITY_MEDIUM;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301816 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001817
Brian Gixfdd38922011-09-28 16:23:48 -07001818 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1819 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001820 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1821 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001822 } else {
1823 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1824 if (io_cap == 0x04)
1825 io_cap = 0x01;
1826 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1827 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301828 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001829 }
Johan Hedberg1425acb2011-11-11 00:07:35 +02001830
Ville Tervo30e76272011-02-22 16:10:53 -03001831 if (IS_ERR(conn)) {
1832 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 goto unlock;
1834 }
1835
1836 if (conn->connect_cfm_cb) {
1837 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001838 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839 goto unlock;
1840 }
1841
Szymon Janc4e51eae2011-02-25 19:05:48 +01001842 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843 if (!cmd) {
1844 err = -ENOMEM;
1845 hci_conn_put(conn);
1846 goto unlock;
1847 }
1848
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001849 conn->connect_cfm_cb = pairing_connect_complete_cb;
1850 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001851 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001852 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001853 cmd->user_data = conn;
1854
1855 if (conn->state == BT_CONNECTED &&
1856 hci_conn_security(conn, sec_level, auth_type))
1857 pairing_complete(cmd, 0);
1858
1859 err = 0;
1860
1861unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001862 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001863 hci_dev_put(hdev);
1864
1865 return err;
1866}
1867
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001869 u16 len, u16 opcode)
Johan Hedberg28424702012-02-02 04:02:29 +02001870{
Johan Hedberga5c29682011-02-19 12:05:57 -03001871 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001872 u16 mgmt_op = opcode, hci_op;
Johan Hedberg28424702012-02-02 04:02:29 +02001873 struct pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03001874 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001875 struct hci_conn *le_conn;
Johan Hedberg28424702012-02-02 04:02:29 +02001876 int err;
1877
Brian Gixa68668b2011-08-11 15:49:36 -07001878 BT_DBG("%d", mgmt_op);
Johan Hedberg28424702012-02-02 04:02:29 +02001879
Brian Gixa68668b2011-08-11 15:49:36 -07001880 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001881 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Johan Hedberg272d90d2012-02-09 15:26:12 +02001882 else
Brian Gixa68668b2011-08-11 15:49:36 -07001883 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Brian Gix47c15e22011-11-16 13:53:14 -08001884
Brian Gixa68668b2011-08-11 15:49:36 -07001885 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001886 return cmd_status(sk, index, mgmt_op, EINVAL);
1887
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001889 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001891
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001892 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001893
Johan Hedberga5c29682011-02-19 12:05:57 -03001894 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberg272d90d2012-02-09 15:26:12 +02001896 goto done;
1897 }
1898
Brian Gixa68668b2011-08-11 15:49:36 -07001899 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1900 if (le_conn) {
1901 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
Brian Gix47c15e22011-11-16 13:53:14 -08001902 goto done;
1903 }
Brian Gixa68668b2011-08-11 15:49:36 -07001904 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1905 "Reject" : "Accept");
Brian Gix47c15e22011-11-16 13:53:14 -08001906
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001908 if (!cmd) {
1909 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001910 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001911 }
1912
Brian Gixa68668b2011-08-11 15:49:36 -07001913 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001914 if (err < 0)
1915 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001916
Brian Gix0df4c182011-11-16 13:53:13 -08001917done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001918 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001919 hci_dev_put(hdev);
1920
Johan Hedberga5c29682011-02-19 12:05:57 -03001921 return err;
1922}
1923
Brian Gixa68668b2011-08-11 15:49:36 -07001924static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1925 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08001926{
Brian Gixa68668b2011-08-11 15:49:36 -07001927 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1928 struct hci_cp_remote_name_req hci_cp;
1929 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001930 struct pending_cmd *cmd;
1931 int err;
1932
1933 BT_DBG("");
1934
Brian Gixa68668b2011-08-11 15:49:36 -07001935 if (len != sizeof(*mgmt_cp))
1936 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001937
Brian Gixa68668b2011-08-11 15:49:36 -07001938 hdev = hci_dev_get(index);
1939 if (!hdev)
1940 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001941
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001942 hci_dev_lock_bh(hdev);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001943
Brian Gixa68668b2011-08-11 15:49:36 -07001944 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001945 if (!cmd) {
1946 err = -ENOMEM;
1947 goto failed;
1948 }
1949
Brian Gixa68668b2011-08-11 15:49:36 -07001950 memset(&hci_cp, 0, sizeof(hci_cp));
1951 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1952 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1953 &hci_cp);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001954 if (err < 0)
1955 mgmt_pending_remove(cmd);
1956
1957failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001958 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001959 hci_dev_put(hdev);
1960
Johan Hedbergb312b1612011-03-16 14:29:37 +02001961 return err;
1962}
1963
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05301964static int cancel_resolve_name(struct sock *sk, u16 index, unsigned char *data,
1965 u16 len)
1966{
1967 struct mgmt_cp_cancel_resolve_name *mgmt_cp = (void *) data;
1968 struct hci_cp_remote_name_req_cancel hci_cp;
1969 struct hci_dev *hdev;
1970 int err;
1971
1972 BT_DBG("");
1973
1974 if (len != sizeof(*mgmt_cp))
1975 return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
1976 EINVAL);
1977
1978 hdev = hci_dev_get(index);
1979 if (!hdev)
1980 return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
1981 ENODEV);
1982
1983 hci_dev_lock_bh(hdev);
1984
1985 memset(&hci_cp, 0, sizeof(hci_cp));
1986 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1987 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(hci_cp),
1988 &hci_cp);
1989
1990 hci_dev_unlock_bh(hdev);
1991 hci_dev_put(hdev);
1992
1993 return err;
1994}
1995
Brian Gix7f7e16c2011-11-01 16:27:25 -07001996static int set_connection_params(struct sock *sk, u16 index,
1997 unsigned char *data, u16 len)
Szymon Jancc35938b2011-03-22 13:12:21 +01001998{
Brian Gix7f7e16c2011-11-01 16:27:25 -07001999 struct mgmt_cp_set_connection_params *cp = (void *) data;
2000 struct hci_dev *hdev;
2001 struct hci_conn *conn;
2002 int err;
2003
2004 BT_DBG("");
2005
2006 if (len != sizeof(*cp))
2007 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2008 EINVAL);
2009
2010 hdev = hci_dev_get(index);
2011 if (!hdev)
2012 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2013 ENODEV);
2014
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002015 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07002016
2017 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2018 if (!conn) {
2019 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
2020 ENOTCONN);
2021 goto failed;
2022 }
2023
2024 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
2025 le16_to_cpu(cp->interval_max),
2026 le16_to_cpu(cp->slave_latency),
2027 le16_to_cpu(cp->timeout_multiplier));
2028
2029 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
2030
2031failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002032 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07002033 hci_dev_put(hdev);
2034
2035 return err;
2036}
2037
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002038static int set_rssi_reporter(struct sock *sk, u16 index,
2039 unsigned char *data, u16 len)
2040{
2041 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
2042 struct hci_dev *hdev;
2043 struct hci_conn *conn;
2044 int err = 0;
2045
2046 if (len != sizeof(*cp))
2047 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2048 EINVAL);
2049
2050 hdev = hci_dev_get(index);
2051 if (!hdev)
2052 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2053 ENODEV);
2054
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002055 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002056
2057 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2058
2059 if (!conn) {
2060 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2061 ENOTCONN);
2062 goto failed;
2063 }
2064
2065 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
2066 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
2067 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
2068
2069failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002070 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002071 hci_dev_put(hdev);
2072
2073 return err;
2074}
2075
2076static int unset_rssi_reporter(struct sock *sk, u16 index,
2077 unsigned char *data, u16 len)
2078{
2079 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
2080 struct hci_dev *hdev;
2081 struct hci_conn *conn;
2082 int err = 0;
2083
2084 if (len != sizeof(*cp))
2085 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2086 EINVAL);
2087
2088 hdev = hci_dev_get(index);
2089
2090 if (!hdev)
2091 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2092 ENODEV);
2093
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002094 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002095
2096 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2097
2098 if (!conn) {
2099 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2100 ENOTCONN);
2101 goto failed;
2102 }
2103
2104 hci_conn_unset_rssi_reporter(conn);
2105
2106failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002107 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002108 hci_dev_put(hdev);
2109
2110 return err;
2111}
2112
Archana Ramachandran907d5232012-10-02 17:55:55 -07002113static int le_cancel_create_conn(struct sock *sk, u16 index,
2114 unsigned char *data, u16 len)
2115{
2116 struct mgmt_cp_le_cancel_create_conn *cp = (void *) data;
2117 struct hci_dev *hdev;
2118 int err = 0;
2119
2120 if (len != sizeof(*cp))
2121 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2122 EINVAL);
2123
2124 hdev = hci_dev_get(index);
2125
2126 if (!hdev)
2127 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2128 ENODEV);
2129
2130 hci_dev_lock_bh(hdev);
2131
2132 if (!test_bit(HCI_UP, &hdev->flags)) {
2133 err = cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2134 ENETDOWN);
2135 goto failed;
2136 }
2137
2138 hci_le_cancel_create_connect(hdev, &cp->bdaddr);
2139
2140failed:
2141 hci_dev_unlock_bh(hdev);
2142 hci_dev_put(hdev);
2143
2144return err;
2145}
2146
Johan Hedberg03811012010-12-08 00:21:06 +02002147static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
2148 u16 len)
2149{
2150 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
2151 struct hci_cp_write_local_name hci_cp;
2152 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01002153 struct pending_cmd *cmd;
2154 int err;
2155
Johan Hedberg03811012010-12-08 00:21:06 +02002156 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01002157
Johan Hedberg03811012010-12-08 00:21:06 +02002158 if (len != sizeof(*mgmt_cp))
2159 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01002160
Johan Hedberg03811012010-12-08 00:21:06 +02002161 hdev = hci_dev_get(index);
2162 if (!hdev)
2163 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
2164
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002165 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002166
2167 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
2168 if (!cmd) {
2169 err = -ENOMEM;
2170 goto failed;
2171 }
2172
2173 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2174 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2175 &hci_cp);
2176 if (err < 0)
2177 mgmt_pending_remove(cmd);
2178
2179failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002180 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002181 hci_dev_put(hdev);
2182
2183 return err;
2184}
2185
Brian Gixa68668b2011-08-11 15:49:36 -07002186static void discovery_rsp(struct pending_cmd *cmd, void *data)
2187{
2188 struct mgmt_mode ev;
2189
2190 BT_DBG("");
2191 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
2192 ev.val = 1;
2193 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
2194 } else {
2195 ev.val = 0;
2196 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
2197 NULL, 0);
2198 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08002199 struct hci_dev *hdev = hci_dev_get(cmd->index);
2200 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08002201 del_timer(&hdev->disco_le_timer);
2202 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08002203 hci_dev_put(hdev);
2204 }
Brian Gixa68668b2011-08-11 15:49:36 -07002205 }
2206 }
2207
2208 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
2209
2210 list_del(&cmd->list);
2211
2212 mgmt_pending_free(cmd);
2213}
2214
2215void mgmt_inquiry_started(u16 index)
2216{
2217 BT_DBG("");
2218 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
2219 discovery_rsp, NULL);
2220}
2221
2222void mgmt_inquiry_complete_evt(u16 index, u8 status)
2223{
2224 struct hci_dev *hdev;
2225 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08002226 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002227 int err = -1;
2228
Brian Gixa68668b2011-08-11 15:49:36 -07002229 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07002230
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302231 if (hdev)
2232 BT_DBG("disco_state: %d", hdev->disco_state);
2233
Brian Gixa68668b2011-08-11 15:49:36 -07002234 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07002235
2236 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2237 discovery_terminated, NULL);
2238
2239 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002240
Anantha Krishnan91b11ff2013-01-27 18:20:20 +05302241 if (hdev) {
2242 BT_DBG("Setting state to SCAN_IDLE\n");
2243 hdev->disco_state = SCAN_IDLE;
Brian Gix64bd5302011-09-08 11:35:48 -07002244 goto done;
Anantha Krishnan91b11ff2013-01-27 18:20:20 +05302245 }
Brian Gix64bd5302011-09-08 11:35:48 -07002246 else
2247 return;
2248 }
Brian Gixa68668b2011-08-11 15:49:36 -07002249
Brian Gix568dde92012-01-11 16:18:04 -08002250 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002251 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2252 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002253 if (err >= 0) {
2254 mod_timer(&hdev->disco_le_timer, jiffies +
2255 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2256 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002257 } else
Brian Gix568dde92012-01-11 16:18:04 -08002258 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002259 }
2260
Brian Gix568dde92012-01-11 16:18:04 -08002261 if (hdev->disco_state == SCAN_IDLE)
2262 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2263
Brian Gixa68668b2011-08-11 15:49:36 -07002264 if (err < 0)
2265 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2266 discovery_terminated, NULL);
2267
Brian Gix64bd5302011-09-08 11:35:48 -07002268done:
Brian Gixa68668b2011-08-11 15:49:36 -07002269 hci_dev_put(hdev);
2270}
2271
Brian Gix568dde92012-01-11 16:18:04 -08002272void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002273{
Brian Gix568dde92012-01-11 16:18:04 -08002274 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002275 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002276 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002277
Brian Gix568dde92012-01-11 16:18:04 -08002278 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002279
Brian Gix568dde92012-01-11 16:18:04 -08002280 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002281
Brian Gix568dde92012-01-11 16:18:04 -08002282 if (!hdev)
2283 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002284
Brian Gix568dde92012-01-11 16:18:04 -08002285 hci_dev_lock_bh(hdev);
2286 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002287
Brian Gix568dde92012-01-11 16:18:04 -08002288 if (hdev->disco_state != SCAN_IDLE) {
2289 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002290
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302291 if (test_bit(HCI_UP, &hdev->flags)) {
2292 if (hdev->disco_state == SCAN_LE)
2293 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002294 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302295 else
2296 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2297 NULL);
2298 }
Brian Gix568dde92012-01-11 16:18:04 -08002299 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002300 }
Brian Gix568dde92012-01-11 16:18:04 -08002301
2302 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2303
2304 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2305 if (cmd)
2306 mgmt_pending_remove(cmd);
2307
2308 hci_dev_unlock_bh(hdev);
2309 hci_dev_put(hdev);
2310}
2311
2312void mgmt_disco_le_timeout(unsigned long data)
2313{
2314 struct hci_dev *hdev = (void *)data;
2315 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2316
2317 BT_DBG("hci%d", hdev->id);
2318
2319 hdev = hci_dev_get(hdev->id);
2320
2321 if (!hdev)
2322 return;
2323
2324 hci_dev_lock_bh(hdev);
2325
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302326 if (test_bit(HCI_UP, &hdev->flags)) {
2327 if (hdev->disco_state == SCAN_LE)
2328 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2329 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002330
2331 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302332 if (hdev->disco_state != SCAN_IDLE) {
2333 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2334 hdev->disco_int_phase *= 2;
2335 hdev->disco_int_count = 0;
2336 cp.num_rsp = (u8) hdev->disco_int_phase;
2337 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2338 hdev->disco_state = SCAN_BR;
2339 }
Brian Gix568dde92012-01-11 16:18:04 -08002340 }
2341
2342 hci_dev_unlock_bh(hdev);
2343 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002344}
2345
2346static int start_discovery(struct sock *sk, u16 index)
2347{
2348 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2349 struct hci_dev *hdev;
2350 struct pending_cmd *cmd;
2351 int err;
2352
2353 BT_DBG("");
2354
2355 hdev = hci_dev_get(index);
2356 if (!hdev)
2357 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2358
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302359 BT_DBG("disco_state: %d", hdev->disco_state);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002360 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002361
Brian Gix568dde92012-01-11 16:18:04 -08002362 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2363 err = -EBUSY;
2364 goto failed;
2365 }
2366
Brian Gixa68668b2011-08-11 15:49:36 -07002367 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2368 if (!cmd) {
2369 err = -ENOMEM;
2370 goto failed;
2371 }
2372
2373 /* If LE Capable, we will alternate between BR/EDR and LE */
2374 if (lmp_le_capable(hdev)) {
2375 struct hci_cp_le_set_scan_parameters le_cp;
2376
2377 /* Shorten BR scan params */
2378 cp.num_rsp = 1;
2379 cp.length /= 2;
2380
2381 /* Setup LE scan params */
2382 memset(&le_cp, 0, sizeof(le_cp));
2383 le_cp.type = 0x01; /* Active scanning */
2384 /* The recommended value for scan interval and window is
2385 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2386 le_cp.interval = cpu_to_le16(0x0012);
2387 le_cp.window = cpu_to_le16(0x0012);
2388 le_cp.own_bdaddr_type = 0; /* Public address */
2389 le_cp.filter = 0; /* Accept all adv packets */
2390
2391 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2392 sizeof(le_cp), &le_cp);
2393 }
2394
2395 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2396
Bhasker Neti09760742012-05-25 12:30:39 +05302397 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002398 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302399 hdev->disco_state = SCAN_IDLE;
2400 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002401 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2402 if (!cmd)
2403 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2404 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002405 hdev->disco_int_phase = 1;
2406 hdev->disco_int_count = 0;
2407 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002408 del_timer(&hdev->disco_le_timer);
2409 del_timer(&hdev->disco_timer);
2410 mod_timer(&hdev->disco_timer,
2411 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302412 } else
2413 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002414
2415failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002416 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002417 hci_dev_put(hdev);
2418
Brian Gix568dde92012-01-11 16:18:04 -08002419 if (err < 0)
2420 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2421
Brian Gixa68668b2011-08-11 15:49:36 -07002422 return err;
2423}
2424
2425static int stop_discovery(struct sock *sk, u16 index)
2426{
2427 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2428 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002429 struct hci_dev *hdev;
2430 struct pending_cmd *cmd = NULL;
2431 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002432 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002433
2434 BT_DBG("");
2435
2436 hdev = hci_dev_get(index);
2437 if (!hdev)
2438 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2439
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302440 BT_DBG("disco_state: %d", hdev->disco_state);
2441
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002442 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002443
Brian Gix568dde92012-01-11 16:18:04 -08002444 state = hdev->disco_state;
2445 hdev->disco_state = SCAN_IDLE;
2446 del_timer(&hdev->disco_le_timer);
2447 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002448
Brian Gix568dde92012-01-11 16:18:04 -08002449 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002450 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2451 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002452 if (err >= 0) {
2453 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2454 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002455
Brian Gix568dde92012-01-11 16:18:04 -08002456 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2457 NULL, 0);
2458 }
Bhasker Neti09760742012-05-25 12:30:39 +05302459 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002460 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002461
Brian Gix568dde92012-01-11 16:18:04 -08002462 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002463 if (err < 0 && cmd)
2464 mgmt_pending_remove(cmd);
2465
2466 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2467
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002468 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002469 hci_dev_put(hdev);
2470
2471 if (err < 0)
2472 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2473 else
2474 return err;
2475}
2476
Szymon Jancc35938b2011-03-22 13:12:21 +01002477static int read_local_oob_data(struct sock *sk, u16 index)
2478{
2479 struct hci_dev *hdev;
2480 struct pending_cmd *cmd;
2481 int err;
2482
2483 BT_DBG("hci%u", index);
2484
2485 hdev = hci_dev_get(index);
2486 if (!hdev)
2487 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2488 ENODEV);
2489
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002490 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002491
2492 if (!test_bit(HCI_UP, &hdev->flags)) {
2493 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2494 ENETDOWN);
2495 goto unlock;
2496 }
2497
2498 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2499 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2500 EOPNOTSUPP);
2501 goto unlock;
2502 }
2503
2504 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2505 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2506 goto unlock;
2507 }
2508
2509 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2510 if (!cmd) {
2511 err = -ENOMEM;
2512 goto unlock;
2513 }
2514
2515 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2516 if (err < 0)
2517 mgmt_pending_remove(cmd);
2518
2519unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002520 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002521 hci_dev_put(hdev);
2522
2523 return err;
2524}
2525
Szymon Janc2763eda2011-03-22 13:12:22 +01002526static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2527 u16 len)
2528{
2529 struct hci_dev *hdev;
2530 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2531 int err;
2532
2533 BT_DBG("hci%u ", index);
2534
2535 if (len != sizeof(*cp))
2536 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2537 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002538
Szymon Janc2763eda2011-03-22 13:12:22 +01002539 hdev = hci_dev_get(index);
2540 if (!hdev)
2541 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2542 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002543
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002544 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002545
2546 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2547 cp->randomizer);
2548 if (err < 0)
2549 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2550 else
2551 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2552 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002553
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002554 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002555 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002556
Szymon Janc2763eda2011-03-22 13:12:22 +01002557 return err;
2558}
2559
2560static int remove_remote_oob_data(struct sock *sk, u16 index,
2561 unsigned char *data, u16 len)
2562{
2563 struct hci_dev *hdev;
2564 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2565 int err;
2566
2567 BT_DBG("hci%u ", index);
2568
2569 if (len != sizeof(*cp))
2570 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2571 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002572
Szymon Janc2763eda2011-03-22 13:12:22 +01002573 hdev = hci_dev_get(index);
2574 if (!hdev)
2575 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2576 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002577
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002578 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002579
2580 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2581 if (err < 0)
2582 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2583 -err);
2584 else
2585 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2586 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002587
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002588 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002589 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002590
2591 return err;
2592}
2593
Johan Hedberg03811012010-12-08 00:21:06 +02002594int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2595{
2596 unsigned char *buf;
2597 struct mgmt_hdr *hdr;
2598 u16 opcode, index, len;
2599 int err;
2600
2601 BT_DBG("got %zu bytes", msglen);
2602
2603 if (msglen < sizeof(*hdr))
2604 return -EINVAL;
2605
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002606 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002607 if (!buf)
2608 return -ENOMEM;
2609
2610 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2611 err = -EFAULT;
2612 goto done;
2613 }
2614
2615 hdr = (struct mgmt_hdr *) buf;
2616 opcode = get_unaligned_le16(&hdr->opcode);
2617 index = get_unaligned_le16(&hdr->index);
2618 len = get_unaligned_le16(&hdr->len);
2619
2620 if (len != msglen - sizeof(*hdr)) {
2621 err = -EINVAL;
2622 goto done;
2623 }
2624
Brian Gixa68668b2011-08-11 15:49:36 -07002625 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002626 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002627 case MGMT_OP_READ_VERSION:
2628 err = read_version(sk);
2629 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002630 case MGMT_OP_READ_INDEX_LIST:
2631 err = read_index_list(sk);
2632 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002633 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002634 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002635 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002636 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002637 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002638 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002639 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002640 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002641 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002642 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2643 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2644 len);
2645 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002646 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002647 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002648 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002649 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002650 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002651 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002652 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002653 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002654 break;
2655 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002656 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002657 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002658 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002659 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002660 break;
2661 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002662 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002663 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002664 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002665 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002666 break;
2667 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002668 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002669 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002670 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002671 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002672 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002673 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002674 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002675 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002676 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002677 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002678 break;
2679 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002680 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002681 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002682 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002683 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002684 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002685 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002686 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002688 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002689 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002690 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002691 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2692 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002693 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002694 case MGMT_OP_SET_LOCAL_NAME:
2695 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2696 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002697 case MGMT_OP_START_DISCOVERY:
2698 err = start_discovery(sk, index);
2699 break;
2700 case MGMT_OP_STOP_DISCOVERY:
2701 err = stop_discovery(sk, index);
2702 break;
2703 case MGMT_OP_RESOLVE_NAME:
2704 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2705 break;
Ram Mohan Korukonda12727612012-11-27 16:13:54 +05302706 case MGMT_OP_CANCEL_RESOLVE_NAME:
2707 err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
2708 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002709 case MGMT_OP_SET_CONNECTION_PARAMS:
2710 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2711 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002712 case MGMT_OP_SET_RSSI_REPORTER:
2713 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2714 break;
2715 case MGMT_OP_UNSET_RSSI_REPORTER:
2716 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2717 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002718 case MGMT_OP_READ_LOCAL_OOB_DATA:
2719 err = read_local_oob_data(sk, index);
2720 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002721 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2722 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2723 break;
2724 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2725 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2726 len);
2727 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302728 case MGMT_OP_ENCRYPT_LINK:
2729 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2730 break;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002731 case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
2732 err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
2733 len);
2734 break;
2735 case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
2736 err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
2737 len);
2738 break;
2739 case MGMT_OP_LE_CLEAR_WHITE_LIST:
2740 err = le_clear_white_list(sk, index);
2741 break;
2742 case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
2743 err = le_create_conn_white_list(sk, index);
2744 break;
2745 case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
2746 err = le_cancel_create_conn_white_list(sk, index);
2747 break;
Archana Ramachandran907d5232012-10-02 17:55:55 -07002748 case MGMT_OP_LE_CANCEL_CREATE_CONN:
2749 err = le_cancel_create_conn(sk, index, buf + sizeof(*hdr), len);
2750 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002751 default:
2752 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002753 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002754 break;
2755 }
2756
Johan Hedberge41d8b42010-12-13 21:07:03 +02002757 if (err < 0)
2758 goto done;
2759
Johan Hedberg03811012010-12-08 00:21:06 +02002760 err = msglen;
2761
2762done:
2763 kfree(buf);
2764 return err;
2765}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002766
Johan Hedbergb24752f2011-11-03 14:40:33 +02002767static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2768{
2769 u8 *status = data;
2770
2771 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2772 mgmt_pending_remove(cmd);
2773}
2774
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002775int mgmt_index_added(u16 index)
2776{
Brian Gixa68668b2011-08-11 15:49:36 -07002777 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002778 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002779}
2780
2781int mgmt_index_removed(u16 index)
2782{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002783 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002784
Brian Gixa68668b2011-08-11 15:49:36 -07002785 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002786
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002787 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2788
Szymon Janc4e51eae2011-02-25 19:05:48 +01002789 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002790}
2791
Johan Hedberg73f22f62010-12-29 16:00:25 +02002792struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002793 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002794 struct sock *sk;
2795};
2796
Johan Hedberg72a734e2010-12-30 00:38:22 +02002797static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002798{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002799 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002800 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002801
Johan Hedberg72a734e2010-12-30 00:38:22 +02002802 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002803 return;
2804
Johan Hedberg053f0212011-01-26 13:07:10 +02002805 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002806
2807 list_del(&cmd->list);
2808
2809 if (match->sk == NULL) {
2810 match->sk = cmd->sk;
2811 sock_hold(match->sk);
2812 }
2813
2814 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002815}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002816
2817int mgmt_powered(u16 index, u8 powered)
2818{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002819 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002820 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002821 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002822
Brian Gixa68668b2011-08-11 15:49:36 -07002823 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002824
Johan Hedberg72a734e2010-12-30 00:38:22 +02002825 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002826
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002827 if (!powered) {
2828 u8 status = ENETDOWN;
2829 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002830 }
2831
Johan Hedberg72a734e2010-12-30 00:38:22 +02002832 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002833
Szymon Janc4e51eae2011-02-25 19:05:48 +01002834 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002835
2836 if (match.sk)
2837 sock_put(match.sk);
2838
2839 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002840}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002841
Johan Hedberg73f22f62010-12-29 16:00:25 +02002842int mgmt_discoverable(u16 index, u8 discoverable)
2843{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002844 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002845 struct cmd_lookup match = { discoverable, NULL };
2846 int ret;
2847
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002848 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002849
Johan Hedberg73f22f62010-12-29 16:00:25 +02002850 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002851
Szymon Janc4e51eae2011-02-25 19:05:48 +01002852 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2853 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002854
Johan Hedberg73f22f62010-12-29 16:00:25 +02002855 if (match.sk)
2856 sock_put(match.sk);
2857
2858 return ret;
2859}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002860
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002861int mgmt_connectable(u16 index, u8 connectable)
2862{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002863 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002864 struct cmd_lookup match = { connectable, NULL };
2865 int ret;
2866
Johan Hedberg72a734e2010-12-30 00:38:22 +02002867 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002868
Johan Hedberg03811012010-12-08 00:21:06 +02002869 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002870
Szymon Janc4e51eae2011-02-25 19:05:48 +01002871 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002872
2873 if (match.sk)
2874 sock_put(match.sk);
2875
2876 return ret;
2877}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002878
Brian Gixa68668b2011-08-11 15:49:36 -07002879int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002880{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002881 struct mgmt_ev_new_key *ev;
2882 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002883
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002884 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2885 ev = kzalloc(total, GFP_ATOMIC);
2886 if (!ev)
2887 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002888
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002889 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002890 ev->key.addr_type = key->addr_type;
2891 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002892 memcpy(ev->key.val, key->val, 16);
2893 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002894 ev->key.auth = key->auth;
2895 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002896 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002897
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002898 memcpy(ev->key.data, key->data, key->dlen);
2899
2900 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2901
2902 kfree(ev);
2903
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002904 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002905}
2906
Brian Gix2e2f50d2011-09-13 12:36:04 -07002907int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002908{
Johan Hedbergf7520542011-01-20 12:34:39 +02002909 struct mgmt_ev_connected ev;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002910 struct pending_cmd *cmd;
2911 struct hci_dev *hdev;
2912
2913 BT_DBG("hci%u", index);
2914
2915 hdev = hci_dev_get(index);
2916
2917 if (!hdev)
2918 return -ENODEV;
Johan Hedbergca69b792011-11-11 18:10:00 +02002919
Johan Hedbergf7520542011-01-20 12:34:39 +02002920 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002921 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002922
Sunny Kapdi93bef892012-07-30 14:52:56 -07002923 cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
2924 if (cmd) {
2925 BT_ERR("mgmt_connected remove mgmt pending white_list");
2926 mgmt_pending_remove(cmd);
2927 }
2928
Szymon Janc4e51eae2011-02-25 19:05:48 +01002929 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002930}
2931
Sunny Kapdia42b5022012-07-05 22:48:31 -07002932int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
2933 u16 latency, u16 timeout)
2934{
2935 struct mgmt_ev_le_conn_params ev;
2936
2937 bacpy(&ev.bdaddr, bdaddr);
2938 ev.interval = interval;
2939 ev.latency = latency;
2940 ev.timeout = timeout;
2941
2942 return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
2943 NULL);
2944}
2945
Johan Hedberg8962ee72011-01-20 12:40:27 +02002946static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2947{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002948 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002949 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002950 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002951
Johan Hedberga38528f2011-01-22 06:46:43 +02002952 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953
Szymon Janc4e51eae2011-02-25 19:05:48 +01002954 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002955
2956 *sk = cmd->sk;
2957 sock_hold(*sk);
2958
Johan Hedberga664b5b2011-02-19 12:06:02 -03002959 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002960}
2961
Archana Ramachandranda09d262012-08-14 12:03:01 -07002962int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002963{
Johan Hedbergf7520542011-01-20 12:34:39 +02002964 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002965 struct sock *sk = NULL;
2966 int err;
2967
Johan Hedbergf7520542011-01-20 12:34:39 +02002968 bacpy(&ev.bdaddr, bdaddr);
Archana Ramachandranda09d262012-08-14 12:03:01 -07002969 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02002970
Szymon Janc4e51eae2011-02-25 19:05:48 +01002971 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002972
2973 if (sk)
2974 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002975
Archana Ramachandranda09d262012-08-14 12:03:01 -07002976 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
2977
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978 return err;
2979}
2980
2981int mgmt_disconnect_failed(u16 index)
2982{
2983 struct pending_cmd *cmd;
2984 int err;
2985
2986 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2987 if (!cmd)
2988 return -ENOENT;
2989
Szymon Janc4e51eae2011-02-25 19:05:48 +01002990 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002991
Johan Hedberga664b5b2011-02-19 12:06:02 -03002992 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002993
2994 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002995}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002996
2997int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2998{
2999 struct mgmt_ev_connect_failed ev;
3000
Johan Hedberg17d5c042011-01-22 06:09:08 +02003001 bacpy(&ev.bdaddr, bdaddr);
3002 ev.status = status;
3003
Szymon Janc4e51eae2011-02-25 19:05:48 +01003004 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003005}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003008{
3009 struct mgmt_ev_pin_code_request ev;
3010
Brian Gixa68668b2011-08-11 15:49:36 -07003011 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003012
Johan Hedberg980e1a52011-01-22 06:10:07 +02003013 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003014 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003015
Szymon Janc4e51eae2011-02-25 19:05:48 +01003016 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
3017 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003018}
3019
3020int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3021{
3022 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003023 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003024 int err;
3025
3026 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
3027 if (!cmd)
3028 return -ENOENT;
3029
Johan Hedbergac56fb12011-02-19 12:05:59 -03003030 bacpy(&rp.bdaddr, bdaddr);
3031 rp.status = status;
3032
Szymon Janc4e51eae2011-02-25 19:05:48 +01003033 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
3034 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003035
Johan Hedberga664b5b2011-02-19 12:06:02 -03003036 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003037
3038 return err;
3039}
3040
3041int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3042{
3043 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003044 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003045 int err;
3046
3047 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
3048 if (!cmd)
3049 return -ENOENT;
3050
Johan Hedbergac56fb12011-02-19 12:05:59 -03003051 bacpy(&rp.bdaddr, bdaddr);
3052 rp.status = status;
3053
Szymon Janc4e51eae2011-02-25 19:05:48 +01003054 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
3055 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056
Johan Hedberga664b5b2011-02-19 12:06:02 -03003057 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003058
3059 return err;
3060}
Johan Hedberga5c29682011-02-19 12:05:57 -03003061
Brian Gixa68668b2011-08-11 15:49:36 -07003062int mgmt_user_confirm_request(u16 index, u8 event,
3063 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03003064{
3065 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07003066 struct hci_conn *conn = NULL;
3067 struct hci_dev *hdev;
3068 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03003069
Brian Gixa68668b2011-08-11 15:49:36 -07003070 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03003071
Brian Gixa68668b2011-08-11 15:49:36 -07003072 hdev = hci_dev_get(index);
3073
Brian Gix64bd5302011-09-08 11:35:48 -07003074 if (!hdev)
3075 return -ENODEV;
3076
Brian Gix64bd5302011-09-08 11:35:48 -07003077 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003078
3079 ev.auto_confirm = 0;
3080
3081 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
3082 goto no_auto_confirm;
3083
3084 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
3085 rem_cap = conn->remote_cap;
3086 loc_mitm = conn->auth_type & 0x01;
3087 rem_mitm = conn->remote_auth & 0x01;
3088
Brian Gixdbf59292011-11-11 15:45:17 -08003089 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
3090 conn->auth_initiator && rem_cap == 0x03)
3091 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303092 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
3093 if (!loc_mitm && !rem_mitm)
3094 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07003095 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303096 }
Brian Gixa68668b2011-08-11 15:49:36 -07003097
Bhasker Netif8fffe82012-10-25 17:42:12 +05303098 /* Show bonding dialog if neither side requires no bonding */
3099 if ((conn->auth_type > 0x01) && (conn->remote_auth > 0x01)) {
3100 if (!loc_mitm && !rem_mitm)
3101 value = 0;
3102 goto no_auto_confirm;
3103 }
Brian Gixa68668b2011-08-11 15:49:36 -07003104
3105 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
3106 ev.auto_confirm = 1;
3107
3108no_auto_confirm:
3109 bacpy(&ev.bdaddr, bdaddr);
3110 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03003111 put_unaligned_le32(value, &ev.value);
3112
Brian Gix64bd5302011-09-08 11:35:48 -07003113 hci_dev_put(hdev);
3114
Brian Gixa68668b2011-08-11 15:49:36 -07003115 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
3116 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003117}
3118
Brian Gixa68668b2011-08-11 15:49:36 -07003119int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08003120{
3121 struct mgmt_ev_user_passkey_request ev;
3122
Johan Hedberga5c29682011-02-19 12:05:57 -03003123 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08003124
Johan Hedberga5c29682011-02-19 12:05:57 -03003125 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003126
Brian Gixa68668b2011-08-11 15:49:36 -07003127 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03003128 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003129}
3130
Johan Hedberga5c29682011-02-19 12:05:57 -03003131static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
3132 u8 opcode)
3133{
3134 struct pending_cmd *cmd;
3135 struct mgmt_rp_user_confirm_reply rp;
3136 int err;
3137
3138 cmd = mgmt_pending_find(opcode, index);
3139 if (!cmd)
3140 return -ENOENT;
3141
Johan Hedberga5c29682011-02-19 12:05:57 -03003142 bacpy(&rp.bdaddr, bdaddr);
3143 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003144 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003145
Johan Hedberga664b5b2011-02-19 12:06:02 -03003146 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003147
3148 return err;
3149}
3150
3151int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3152{
3153 return confirm_reply_complete(index, bdaddr, status,
3154 MGMT_OP_USER_CONFIRM_REPLY);
3155}
3156
Szymon Jancb8534e0f2011-03-01 16:55:34 +01003157int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003158{
3159 return confirm_reply_complete(index, bdaddr, status,
3160 MGMT_OP_USER_CONFIRM_NEG_REPLY);
3161}
Johan Hedberg2a611692011-02-19 12:06:00 -03003162
3163int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3164{
3165 struct mgmt_ev_auth_failed ev;
3166
Johan Hedberg2a611692011-02-19 12:06:00 -03003167 bacpy(&ev.bdaddr, bdaddr);
3168 ev.status = status;
3169
Szymon Janc4e51eae2011-02-25 19:05:48 +01003170 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003171}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003172
3173int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
3174{
3175 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003176 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003177 struct mgmt_cp_set_local_name ev;
3178 int err;
3179
3180 memset(&ev, 0, sizeof(ev));
3181 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3182
3183 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
3184 if (!cmd)
3185 goto send_event;
3186
3187 if (status) {
3188 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
3189 goto failed;
3190 }
3191
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003192 hdev = hci_dev_get(index);
3193 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003194 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003195 hci_dev_put(hdev);
3196 }
3197
Johan Hedbergb312b1612011-03-16 14:29:37 +02003198 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
3199 sizeof(ev));
3200 if (err < 0)
3201 goto failed;
3202
3203send_event:
3204 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
3205 cmd ? cmd->sk : NULL);
3206
3207failed:
3208 if (cmd)
3209 mgmt_pending_remove(cmd);
3210 return err;
3211}
Szymon Jancc35938b2011-03-22 13:12:21 +01003212
3213int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
3214 u8 status)
3215{
3216 struct pending_cmd *cmd;
3217 int err;
3218
3219 BT_DBG("hci%u status %u", index, status);
3220
3221 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
3222 if (!cmd)
3223 return -ENOENT;
3224
3225 if (status) {
3226 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3227 EIO);
3228 } else {
3229 struct mgmt_rp_read_local_oob_data rp;
3230
3231 memcpy(rp.hash, hash, sizeof(rp.hash));
3232 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3233
3234 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3235 &rp, sizeof(rp));
3236 }
3237
3238 mgmt_pending_remove(cmd);
3239
3240 return err;
3241}
Johan Hedberge17acd42011-03-30 23:57:16 +03003242
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003243void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
3244 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02003245{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003246 struct mgmt_ev_rssi_update ev;
3247 struct hci_conn *conn;
3248 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003249
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003250 if (status)
3251 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003252
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003253 hdev = hci_dev_get(index);
3254 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003255
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003256 if (!conn)
3257 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003258
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003259 BT_DBG("rssi_update_thresh_exceed : %d ",
3260 conn->rssi_update_thresh_exceed);
3261 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
3262 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003263
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003264 if (conn->rssi_update_thresh_exceed == 1) {
3265 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003266 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003267 memset(&ev, 0, sizeof(ev));
3268 bacpy(&ev.bdaddr, bdaddr);
3269 ev.rssi = rssi;
3270 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3271 sizeof(ev), NULL);
3272 } else {
3273 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3274 conn->rssi_update_interval,
3275 conn->rssi_update_thresh_exceed);
3276 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003277 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003278 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003279 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003280 memset(&ev, 0, sizeof(ev));
3281 bacpy(&ev.bdaddr, bdaddr);
3282 ev.rssi = rssi;
3283 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3284 sizeof(ev), NULL);
3285 } else {
3286 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3287 conn->rssi_update_interval,
3288 conn->rssi_update_thresh_exceed);
3289 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003290 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003291}
3292
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003293
Brian Gixa68668b2011-08-11 15:49:36 -07003294int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
3295 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03003296{
3297 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08003298 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003299 int err;
3300
Brian Gixa68668b2011-08-11 15:49:36 -07003301 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003302
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003303 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003304
Johan Hedberge17acd42011-03-30 23:57:16 +03003305 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03003306 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07003307 ev.type = type;
3308 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03003309
Brian Gixa68668b2011-08-11 15:49:36 -07003310 if (dev_class)
3311 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03003312
Brian Gixa68668b2011-08-11 15:49:36 -07003313 if (eir && eir_len)
3314 memcpy(ev.eir, eir, eir_len);
3315
3316 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3317
3318 if (err < 0)
3319 return err;
3320
Brian Gix568dde92012-01-11 16:18:04 -08003321 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003322
Brian Gix568dde92012-01-11 16:18:04 -08003323 if (!hdev)
3324 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003325
Brian Gix568dde92012-01-11 16:18:04 -08003326 if (hdev->disco_state == SCAN_IDLE)
3327 goto done;
3328
3329 hdev->disco_int_count++;
3330
3331 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3332 /* Inquiry scan for General Discovery LAP */
3333 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3334 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3335
3336 hdev->disco_int_phase *= 2;
3337 hdev->disco_int_count = 0;
3338 if (hdev->disco_state == SCAN_LE) {
3339 /* cancel LE scan */
3340 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3341 sizeof(le_cp), &le_cp);
3342 /* start BR scan */
3343 cp.num_rsp = (u8) hdev->disco_int_phase;
3344 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3345 sizeof(cp), &cp);
3346 hdev->disco_state = SCAN_BR;
3347 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003348 }
3349 }
3350
Brian Gix568dde92012-01-11 16:18:04 -08003351done:
3352 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003353 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003354}
Antti Julku5e762442011-08-25 16:48:02 +03003355
Brian Gixa68668b2011-08-11 15:49:36 -07003356
3357int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003358{
Johan Hedberga88a9652011-03-30 13:18:12 +03003359 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003360
Johan Hedberga88a9652011-03-30 13:18:12 +03003361 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003362
Johan Hedberga88a9652011-03-30 13:18:12 +03003363 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003364 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003365 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003366
Johan Hedberga88a9652011-03-30 13:18:12 +03003367 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003368}
3369
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303370int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003371{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303372 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003373
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303374 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003375
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303376 bacpy(&ev.bdaddr, bdaddr);
3377 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003378
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303379 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3380 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003381}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003382
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303383int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3384{
3385 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003386
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303387 memset(&ev, 0, sizeof(ev));
3388
3389 bacpy(&ev.bdaddr, bdaddr);
3390 memcpy(ev.dev_class, dev_class, 3);
3391
3392 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3393}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303394
3395int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3396 u16 sub_ver)
3397{
3398 struct mgmt_ev_remote_version ev;
3399
3400 memset(&ev, 0, sizeof(ev));
3401
3402 bacpy(&ev.bdaddr, bdaddr);
3403 ev.lmp_ver = ver;
3404 ev.manufacturer = mnf;
3405 ev.lmp_subver = sub_ver;
3406
3407 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3408}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003409
3410int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3411{
3412 struct mgmt_ev_remote_features ev;
3413
3414 memset(&ev, 0, sizeof(ev));
3415
3416 bacpy(&ev.bdaddr, bdaddr);
3417 memcpy(ev.features, features, sizeof(ev.features));
3418
3419 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3420 NULL);
3421}