blob: e731d6d94b6caa480271995725a55a09c301a896 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
Brian Gix568dde92012-01-11 16:18:04 -08004 Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
Johan Hedberg03811012010-12-08 00:21:06 +02005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
24/* Bluetooth HCI Management interface */
25
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/interrupt.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040028#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020029#include <asm/unaligned.h>
30
31#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010039
Brian Gix568dde92012-01-11 16:18:04 -080040#define SCAN_IDLE 0x00
41#define SCAN_LE 0x01
42#define SCAN_BR 0x02
Johan Hedberg4b34ee782012-02-21 14:13:02 +020043
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044struct pending_cmd {
45 struct list_head list;
46 __u16 opcode;
47 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010048 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030050 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020051};
52
Mat Martineau8cd0df02011-08-23 16:23:36 -070053struct mgmt_pending_free_work {
54 struct work_struct work;
55 struct sock *sk;
Johan Hedbergca69b792011-11-11 18:10:00 +020056};
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058LIST_HEAD(cmd_list);
Johan Hedbergca69b792011-11-11 18:10:00 +020059
Szymon Janc4e51eae2011-02-25 19:05:48 +010060static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020061{
62 struct sk_buff *skb;
63 struct mgmt_hdr *hdr;
64 struct mgmt_ev_cmd_status *ev;
65
Szymon Janc34eb5252011-02-28 14:10:08 +010066 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020067
68 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
69 if (!skb)
70 return -ENOMEM;
71
72 hdr = (void *) skb_put(skb, sizeof(*hdr));
73
74 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010075 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076 hdr->len = cpu_to_le16(sizeof(*ev));
77
78 ev = (void *) skb_put(skb, sizeof(*ev));
79 ev->status = status;
80 put_unaligned_le16(cmd, &ev->opcode);
81
82 if (sock_queue_rcv_skb(sk, skb) < 0)
83 kfree_skb(skb);
84
85 return 0;
86}
87
Szymon Janc4e51eae2011-02-25 19:05:48 +010088static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
89 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020090{
91 struct sk_buff *skb;
92 struct mgmt_hdr *hdr;
93 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020094
95 BT_DBG("sock %p", sk);
96
Johan Hedberga38528f2011-01-22 06:46:43 +020097 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020098 if (!skb)
99 return -ENOMEM;
100
101 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200102
Johan Hedberg02d98122010-12-13 21:07:04 +0200103 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100104 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106
Johan Hedberga38528f2011-01-22 06:46:43 +0200107 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
108 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100109
110 if (rp)
111 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200112
113 if (sock_queue_rcv_skb(sk, skb) < 0)
114 kfree_skb(skb);
115
116 return 0;
117}
118
Johan Hedberga38528f2011-01-22 06:46:43 +0200119static int read_version(struct sock *sk)
120{
121 struct mgmt_rp_read_version rp;
122
123 BT_DBG("sock %p", sk);
124
125 rp.version = MGMT_VERSION;
126 put_unaligned_le16(MGMT_REVISION, &rp.revision);
127
Szymon Janc4e51eae2011-02-25 19:05:48 +0100128 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
129 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200130}
131
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132static int read_index_list(struct sock *sk)
133{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134 struct mgmt_rp_read_index_list *rp;
135 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200138 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139
140 BT_DBG("sock %p", sk);
141
142 read_lock(&hci_dev_list_lock);
143
144 count = 0;
145 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
147 if (d->dev_type != HCI_BREDR)
148 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Peter Krystad1fc44072011-08-30 15:38:12 -0700167 if (d->dev_type != HCI_BREDR)
168 continue;
169
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200170 set_bit(HCI_MGMT, &d->flags);
171
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172 if (test_bit(HCI_SETUP, &d->flags))
173 continue;
174
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200175 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700176 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200177 BT_DBG("Added hci%u", d->id);
178 }
179
180 read_unlock(&hci_dev_list_lock);
181
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
183 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200184
Johan Hedberga38528f2011-01-22 06:46:43 +0200185 kfree(rp);
186
187 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200188}
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200191{
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200201 hci_del_off_timer(hdev);
202
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800203 hci_dev_lock_bh(hdev);
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100204
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200205 set_bit(HCI_MGMT, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200207 memset(&rp, 0, sizeof(rp));
208
Johan Hedberga38528f2011-01-22 06:46:43 +0200209 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Johan Hedberga38528f2011-01-22 06:46:43 +0200211 rp.powered = test_bit(HCI_UP, &hdev->flags);
212 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
213 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
214 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200221 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222
Johan Hedberga38528f2011-01-22 06:46:43 +0200223 bacpy(&rp.bdaddr, &hdev->bdaddr);
224 memcpy(rp.features, hdev->features, 8);
225 memcpy(rp.dev_class, hdev->dev_class, 3);
226 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
227 rp.hci_ver = hdev->hci_ver;
228 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200230 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
231
Sunny Kapdi320598f2012-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 Netif0c2b8f2012-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 Netif0c2b8f2012-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 Kapdi320598f2012-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 Jancb8534e02011-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 Jancb8534e02011-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 Krovvidi94bf88f2012-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 Korukonda6d41bdf2012-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
Johan Hedberg03811012010-12-08 00:21:06 +02002113static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
2114 u16 len)
2115{
2116 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
2117 struct hci_cp_write_local_name hci_cp;
2118 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01002119 struct pending_cmd *cmd;
2120 int err;
2121
Johan Hedberg03811012010-12-08 00:21:06 +02002122 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01002123
Johan Hedberg03811012010-12-08 00:21:06 +02002124 if (len != sizeof(*mgmt_cp))
2125 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01002126
Johan Hedberg03811012010-12-08 00:21:06 +02002127 hdev = hci_dev_get(index);
2128 if (!hdev)
2129 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
2130
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002131 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002132
2133 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
2134 if (!cmd) {
2135 err = -ENOMEM;
2136 goto failed;
2137 }
2138
2139 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2140 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2141 &hci_cp);
2142 if (err < 0)
2143 mgmt_pending_remove(cmd);
2144
2145failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002146 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002147 hci_dev_put(hdev);
2148
2149 return err;
2150}
2151
Brian Gixa68668b2011-08-11 15:49:36 -07002152static void discovery_rsp(struct pending_cmd *cmd, void *data)
2153{
2154 struct mgmt_mode ev;
2155
2156 BT_DBG("");
2157 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
2158 ev.val = 1;
2159 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
2160 } else {
2161 ev.val = 0;
2162 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
2163 NULL, 0);
2164 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08002165 struct hci_dev *hdev = hci_dev_get(cmd->index);
2166 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08002167 del_timer(&hdev->disco_le_timer);
2168 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08002169 hci_dev_put(hdev);
2170 }
Brian Gixa68668b2011-08-11 15:49:36 -07002171 }
2172 }
2173
2174 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
2175
2176 list_del(&cmd->list);
2177
2178 mgmt_pending_free(cmd);
2179}
2180
2181void mgmt_inquiry_started(u16 index)
2182{
2183 BT_DBG("");
2184 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
2185 discovery_rsp, NULL);
2186}
2187
2188void mgmt_inquiry_complete_evt(u16 index, u8 status)
2189{
2190 struct hci_dev *hdev;
2191 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08002192 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002193 int err = -1;
2194
Brian Gixa68668b2011-08-11 15:49:36 -07002195 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07002196
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302197 if (hdev)
2198 BT_DBG("disco_state: %d", hdev->disco_state);
2199
Brian Gixa68668b2011-08-11 15:49:36 -07002200 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07002201
2202 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2203 discovery_terminated, NULL);
2204
2205 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002206
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302207 hdev->disco_state = SCAN_IDLE;
2208
Brian Gix64bd5302011-09-08 11:35:48 -07002209 if (hdev)
2210 goto done;
2211 else
2212 return;
2213 }
Brian Gixa68668b2011-08-11 15:49:36 -07002214
Brian Gix568dde92012-01-11 16:18:04 -08002215 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002216 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2217 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002218 if (err >= 0) {
2219 mod_timer(&hdev->disco_le_timer, jiffies +
2220 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2221 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002222 } else
Brian Gix568dde92012-01-11 16:18:04 -08002223 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002224 }
2225
Brian Gix568dde92012-01-11 16:18:04 -08002226 if (hdev->disco_state == SCAN_IDLE)
2227 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2228
Brian Gixa68668b2011-08-11 15:49:36 -07002229 if (err < 0)
2230 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2231 discovery_terminated, NULL);
2232
Brian Gix64bd5302011-09-08 11:35:48 -07002233done:
Brian Gixa68668b2011-08-11 15:49:36 -07002234 hci_dev_put(hdev);
2235}
2236
Brian Gix568dde92012-01-11 16:18:04 -08002237void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002238{
Brian Gix568dde92012-01-11 16:18:04 -08002239 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002240 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002241 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002242
Brian Gix568dde92012-01-11 16:18:04 -08002243 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002244
Brian Gix568dde92012-01-11 16:18:04 -08002245 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002246
Brian Gix568dde92012-01-11 16:18:04 -08002247 if (!hdev)
2248 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002249
Brian Gix568dde92012-01-11 16:18:04 -08002250 hci_dev_lock_bh(hdev);
2251 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002252
Brian Gix568dde92012-01-11 16:18:04 -08002253 if (hdev->disco_state != SCAN_IDLE) {
2254 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002255
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302256 if (test_bit(HCI_UP, &hdev->flags)) {
2257 if (hdev->disco_state == SCAN_LE)
2258 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002259 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302260 else
2261 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2262 NULL);
2263 }
Brian Gix568dde92012-01-11 16:18:04 -08002264 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002265 }
Brian Gix568dde92012-01-11 16:18:04 -08002266
2267 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2268
2269 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2270 if (cmd)
2271 mgmt_pending_remove(cmd);
2272
2273 hci_dev_unlock_bh(hdev);
2274 hci_dev_put(hdev);
2275}
2276
2277void mgmt_disco_le_timeout(unsigned long data)
2278{
2279 struct hci_dev *hdev = (void *)data;
2280 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2281
2282 BT_DBG("hci%d", hdev->id);
2283
2284 hdev = hci_dev_get(hdev->id);
2285
2286 if (!hdev)
2287 return;
2288
2289 hci_dev_lock_bh(hdev);
2290
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,
2294 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002295
2296 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302297 if (hdev->disco_state != SCAN_IDLE) {
2298 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2299 hdev->disco_int_phase *= 2;
2300 hdev->disco_int_count = 0;
2301 cp.num_rsp = (u8) hdev->disco_int_phase;
2302 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2303 hdev->disco_state = SCAN_BR;
2304 }
Brian Gix568dde92012-01-11 16:18:04 -08002305 }
2306
2307 hci_dev_unlock_bh(hdev);
2308 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002309}
2310
2311static int start_discovery(struct sock *sk, u16 index)
2312{
2313 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2314 struct hci_dev *hdev;
2315 struct pending_cmd *cmd;
2316 int err;
2317
2318 BT_DBG("");
2319
2320 hdev = hci_dev_get(index);
2321 if (!hdev)
2322 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2323
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302324 BT_DBG("disco_state: %d", hdev->disco_state);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002325 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002326
Brian Gix568dde92012-01-11 16:18:04 -08002327 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2328 err = -EBUSY;
2329 goto failed;
2330 }
2331
Brian Gixa68668b2011-08-11 15:49:36 -07002332 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2333 if (!cmd) {
2334 err = -ENOMEM;
2335 goto failed;
2336 }
2337
2338 /* If LE Capable, we will alternate between BR/EDR and LE */
2339 if (lmp_le_capable(hdev)) {
2340 struct hci_cp_le_set_scan_parameters le_cp;
2341
2342 /* Shorten BR scan params */
2343 cp.num_rsp = 1;
2344 cp.length /= 2;
2345
2346 /* Setup LE scan params */
2347 memset(&le_cp, 0, sizeof(le_cp));
2348 le_cp.type = 0x01; /* Active scanning */
2349 /* The recommended value for scan interval and window is
2350 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2351 le_cp.interval = cpu_to_le16(0x0012);
2352 le_cp.window = cpu_to_le16(0x0012);
2353 le_cp.own_bdaddr_type = 0; /* Public address */
2354 le_cp.filter = 0; /* Accept all adv packets */
2355
2356 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2357 sizeof(le_cp), &le_cp);
2358 }
2359
2360 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2361
Bhasker Neti09760742012-05-25 12:30:39 +05302362 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002363 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302364 hdev->disco_state = SCAN_IDLE;
2365 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002366 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2367 if (!cmd)
2368 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2369 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002370 hdev->disco_int_phase = 1;
2371 hdev->disco_int_count = 0;
2372 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002373 del_timer(&hdev->disco_le_timer);
2374 del_timer(&hdev->disco_timer);
2375 mod_timer(&hdev->disco_timer,
2376 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302377 } else
2378 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002379
2380failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002381 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002382 hci_dev_put(hdev);
2383
Brian Gix568dde92012-01-11 16:18:04 -08002384 if (err < 0)
2385 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2386
Brian Gixa68668b2011-08-11 15:49:36 -07002387 return err;
2388}
2389
2390static int stop_discovery(struct sock *sk, u16 index)
2391{
2392 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2393 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002394 struct hci_dev *hdev;
2395 struct pending_cmd *cmd = NULL;
2396 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002397 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002398
2399 BT_DBG("");
2400
2401 hdev = hci_dev_get(index);
2402 if (!hdev)
2403 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2404
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302405 BT_DBG("disco_state: %d", hdev->disco_state);
2406
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002407 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002408
Brian Gix568dde92012-01-11 16:18:04 -08002409 state = hdev->disco_state;
2410 hdev->disco_state = SCAN_IDLE;
2411 del_timer(&hdev->disco_le_timer);
2412 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002413
Brian Gix568dde92012-01-11 16:18:04 -08002414 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002415 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2416 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002417 if (err >= 0) {
2418 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2419 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002420
Brian Gix568dde92012-01-11 16:18:04 -08002421 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2422 NULL, 0);
2423 }
Bhasker Neti09760742012-05-25 12:30:39 +05302424 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002425 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002426
Brian Gix568dde92012-01-11 16:18:04 -08002427 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002428 if (err < 0 && cmd)
2429 mgmt_pending_remove(cmd);
2430
2431 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2432
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002433 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002434 hci_dev_put(hdev);
2435
2436 if (err < 0)
2437 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2438 else
2439 return err;
2440}
2441
Szymon Jancc35938b2011-03-22 13:12:21 +01002442static int read_local_oob_data(struct sock *sk, u16 index)
2443{
2444 struct hci_dev *hdev;
2445 struct pending_cmd *cmd;
2446 int err;
2447
2448 BT_DBG("hci%u", index);
2449
2450 hdev = hci_dev_get(index);
2451 if (!hdev)
2452 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2453 ENODEV);
2454
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002455 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002456
2457 if (!test_bit(HCI_UP, &hdev->flags)) {
2458 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2459 ENETDOWN);
2460 goto unlock;
2461 }
2462
2463 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2464 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2465 EOPNOTSUPP);
2466 goto unlock;
2467 }
2468
2469 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2470 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2471 goto unlock;
2472 }
2473
2474 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2475 if (!cmd) {
2476 err = -ENOMEM;
2477 goto unlock;
2478 }
2479
2480 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2481 if (err < 0)
2482 mgmt_pending_remove(cmd);
2483
2484unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002485 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002486 hci_dev_put(hdev);
2487
2488 return err;
2489}
2490
Szymon Janc2763eda2011-03-22 13:12:22 +01002491static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2492 u16 len)
2493{
2494 struct hci_dev *hdev;
2495 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2496 int err;
2497
2498 BT_DBG("hci%u ", index);
2499
2500 if (len != sizeof(*cp))
2501 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2502 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002503
Szymon Janc2763eda2011-03-22 13:12:22 +01002504 hdev = hci_dev_get(index);
2505 if (!hdev)
2506 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2507 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002508
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002509 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002510
2511 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2512 cp->randomizer);
2513 if (err < 0)
2514 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2515 else
2516 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2517 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002518
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002519 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002520 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002521
Szymon Janc2763eda2011-03-22 13:12:22 +01002522 return err;
2523}
2524
2525static int remove_remote_oob_data(struct sock *sk, u16 index,
2526 unsigned char *data, u16 len)
2527{
2528 struct hci_dev *hdev;
2529 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2530 int err;
2531
2532 BT_DBG("hci%u ", index);
2533
2534 if (len != sizeof(*cp))
2535 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2536 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002537
Szymon Janc2763eda2011-03-22 13:12:22 +01002538 hdev = hci_dev_get(index);
2539 if (!hdev)
2540 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2541 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002542
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002543 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002544
2545 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2546 if (err < 0)
2547 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2548 -err);
2549 else
2550 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2551 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002552
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002553 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002554 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002555
2556 return err;
2557}
2558
Johan Hedberg03811012010-12-08 00:21:06 +02002559int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2560{
2561 unsigned char *buf;
2562 struct mgmt_hdr *hdr;
2563 u16 opcode, index, len;
2564 int err;
2565
2566 BT_DBG("got %zu bytes", msglen);
2567
2568 if (msglen < sizeof(*hdr))
2569 return -EINVAL;
2570
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002571 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002572 if (!buf)
2573 return -ENOMEM;
2574
2575 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2576 err = -EFAULT;
2577 goto done;
2578 }
2579
2580 hdr = (struct mgmt_hdr *) buf;
2581 opcode = get_unaligned_le16(&hdr->opcode);
2582 index = get_unaligned_le16(&hdr->index);
2583 len = get_unaligned_le16(&hdr->len);
2584
2585 if (len != msglen - sizeof(*hdr)) {
2586 err = -EINVAL;
2587 goto done;
2588 }
2589
Brian Gixa68668b2011-08-11 15:49:36 -07002590 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002591 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002592 case MGMT_OP_READ_VERSION:
2593 err = read_version(sk);
2594 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002595 case MGMT_OP_READ_INDEX_LIST:
2596 err = read_index_list(sk);
2597 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002598 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002599 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002600 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002601 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002602 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002603 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002604 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002605 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002606 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002607 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2608 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2609 len);
2610 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002611 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002612 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002613 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002614 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002615 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002616 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002617 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002618 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002619 break;
2620 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002621 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002622 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002623 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002624 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002625 break;
2626 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002627 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002628 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002629 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002630 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002631 break;
2632 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002634 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002635 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002636 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002637 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002638 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002639 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002640 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002641 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002642 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002643 break;
2644 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002645 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002646 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002647 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002648 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002649 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002650 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002651 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002652 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002653 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002654 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002655 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002656 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2657 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002658 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002659 case MGMT_OP_SET_LOCAL_NAME:
2660 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2661 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002662 case MGMT_OP_START_DISCOVERY:
2663 err = start_discovery(sk, index);
2664 break;
2665 case MGMT_OP_STOP_DISCOVERY:
2666 err = stop_discovery(sk, index);
2667 break;
2668 case MGMT_OP_RESOLVE_NAME:
2669 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2670 break;
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302671 case MGMT_OP_CANCEL_RESOLVE_NAME:
2672 err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
2673 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002674 case MGMT_OP_SET_CONNECTION_PARAMS:
2675 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2676 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002677 case MGMT_OP_SET_RSSI_REPORTER:
2678 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2679 break;
2680 case MGMT_OP_UNSET_RSSI_REPORTER:
2681 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2682 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002683 case MGMT_OP_READ_LOCAL_OOB_DATA:
2684 err = read_local_oob_data(sk, index);
2685 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002686 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2687 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2688 break;
2689 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2690 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2691 len);
2692 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302693 case MGMT_OP_ENCRYPT_LINK:
2694 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2695 break;
Sunny Kapdi320598f2012-07-30 14:52:56 -07002696 case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
2697 err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
2698 len);
2699 break;
2700 case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
2701 err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
2702 len);
2703 break;
2704 case MGMT_OP_LE_CLEAR_WHITE_LIST:
2705 err = le_clear_white_list(sk, index);
2706 break;
2707 case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
2708 err = le_create_conn_white_list(sk, index);
2709 break;
2710 case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
2711 err = le_cancel_create_conn_white_list(sk, index);
2712 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002713 default:
2714 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002715 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002716 break;
2717 }
2718
Johan Hedberge41d8b42010-12-13 21:07:03 +02002719 if (err < 0)
2720 goto done;
2721
Johan Hedberg03811012010-12-08 00:21:06 +02002722 err = msglen;
2723
2724done:
2725 kfree(buf);
2726 return err;
2727}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002728
Johan Hedbergb24752f2011-11-03 14:40:33 +02002729static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2730{
2731 u8 *status = data;
2732
2733 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2734 mgmt_pending_remove(cmd);
2735}
2736
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002737int mgmt_index_added(u16 index)
2738{
Brian Gixa68668b2011-08-11 15:49:36 -07002739 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002740 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002741}
2742
2743int mgmt_index_removed(u16 index)
2744{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002745 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002746
Brian Gixa68668b2011-08-11 15:49:36 -07002747 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002748
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002749 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2750
Szymon Janc4e51eae2011-02-25 19:05:48 +01002751 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002752}
2753
Johan Hedberg73f22f62010-12-29 16:00:25 +02002754struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002755 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002756 struct sock *sk;
2757};
2758
Johan Hedberg72a734e2010-12-30 00:38:22 +02002759static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002760{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002761 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002762 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002763
Johan Hedberg72a734e2010-12-30 00:38:22 +02002764 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765 return;
2766
Johan Hedberg053f0212011-01-26 13:07:10 +02002767 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002768
2769 list_del(&cmd->list);
2770
2771 if (match->sk == NULL) {
2772 match->sk = cmd->sk;
2773 sock_hold(match->sk);
2774 }
2775
2776 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002777}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002778
2779int mgmt_powered(u16 index, u8 powered)
2780{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002781 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002782 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002783 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002784
Brian Gixa68668b2011-08-11 15:49:36 -07002785 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002786
Johan Hedberg72a734e2010-12-30 00:38:22 +02002787 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002788
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002789 if (!powered) {
2790 u8 status = ENETDOWN;
2791 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002792 }
2793
Johan Hedberg72a734e2010-12-30 00:38:22 +02002794 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002795
Szymon Janc4e51eae2011-02-25 19:05:48 +01002796 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002797
2798 if (match.sk)
2799 sock_put(match.sk);
2800
2801 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002802}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002803
Johan Hedberg73f22f62010-12-29 16:00:25 +02002804int mgmt_discoverable(u16 index, u8 discoverable)
2805{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002806 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002807 struct cmd_lookup match = { discoverable, NULL };
2808 int ret;
2809
Szymon Jancb8534e02011-03-01 16:55:34 +01002810 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002811
Johan Hedberg73f22f62010-12-29 16:00:25 +02002812 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002813
Szymon Janc4e51eae2011-02-25 19:05:48 +01002814 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2815 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002816
Johan Hedberg73f22f62010-12-29 16:00:25 +02002817 if (match.sk)
2818 sock_put(match.sk);
2819
2820 return ret;
2821}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002822
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002823int mgmt_connectable(u16 index, u8 connectable)
2824{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002825 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002826 struct cmd_lookup match = { connectable, NULL };
2827 int ret;
2828
Johan Hedberg72a734e2010-12-30 00:38:22 +02002829 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002830
Johan Hedberg03811012010-12-08 00:21:06 +02002831 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002832
Szymon Janc4e51eae2011-02-25 19:05:48 +01002833 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002834
2835 if (match.sk)
2836 sock_put(match.sk);
2837
2838 return ret;
2839}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002840
Brian Gixa68668b2011-08-11 15:49:36 -07002841int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002842{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002843 struct mgmt_ev_new_key *ev;
2844 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002845
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002846 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2847 ev = kzalloc(total, GFP_ATOMIC);
2848 if (!ev)
2849 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002850
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002851 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002852 ev->key.addr_type = key->addr_type;
2853 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002854 memcpy(ev->key.val, key->val, 16);
2855 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002856 ev->key.auth = key->auth;
2857 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002858 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002859
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002860 memcpy(ev->key.data, key->data, key->dlen);
2861
2862 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2863
2864 kfree(ev);
2865
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002866 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002867}
2868
Brian Gix2e2f50d2011-09-13 12:36:04 -07002869int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002870{
Johan Hedbergf7520542011-01-20 12:34:39 +02002871 struct mgmt_ev_connected ev;
Sunny Kapdi320598f2012-07-30 14:52:56 -07002872 struct pending_cmd *cmd;
2873 struct hci_dev *hdev;
2874
2875 BT_DBG("hci%u", index);
2876
2877 hdev = hci_dev_get(index);
2878
2879 if (!hdev)
2880 return -ENODEV;
Johan Hedbergca69b792011-11-11 18:10:00 +02002881
Johan Hedbergf7520542011-01-20 12:34:39 +02002882 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002883 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002884
Sunny Kapdi320598f2012-07-30 14:52:56 -07002885 cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
2886 if (cmd) {
2887 BT_ERR("mgmt_connected remove mgmt pending white_list");
2888 mgmt_pending_remove(cmd);
2889 }
2890
Szymon Janc4e51eae2011-02-25 19:05:48 +01002891 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002892}
2893
Sunny Kapdia42b5022012-07-05 22:48:31 -07002894int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
2895 u16 latency, u16 timeout)
2896{
2897 struct mgmt_ev_le_conn_params ev;
2898
2899 bacpy(&ev.bdaddr, bdaddr);
2900 ev.interval = interval;
2901 ev.latency = latency;
2902 ev.timeout = timeout;
2903
2904 return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
2905 NULL);
2906}
2907
Johan Hedberg8962ee72011-01-20 12:40:27 +02002908static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2909{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002910 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002911 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002912 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002913
Johan Hedberga38528f2011-01-22 06:46:43 +02002914 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002915
Szymon Janc4e51eae2011-02-25 19:05:48 +01002916 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002917
2918 *sk = cmd->sk;
2919 sock_hold(*sk);
2920
Johan Hedberga664b5b2011-02-19 12:06:02 -03002921 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002922}
2923
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002924int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002925{
Johan Hedbergf7520542011-01-20 12:34:39 +02002926 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002927 struct sock *sk = NULL;
2928 int err;
2929
Johan Hedbergf7520542011-01-20 12:34:39 +02002930 bacpy(&ev.bdaddr, bdaddr);
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002931 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02002932
Szymon Janc4e51eae2011-02-25 19:05:48 +01002933 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002934
2935 if (sk)
2936 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002937
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002938 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
2939
Johan Hedberg8962ee72011-01-20 12:40:27 +02002940 return err;
2941}
2942
2943int mgmt_disconnect_failed(u16 index)
2944{
2945 struct pending_cmd *cmd;
2946 int err;
2947
2948 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2949 if (!cmd)
2950 return -ENOENT;
2951
Szymon Janc4e51eae2011-02-25 19:05:48 +01002952 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953
Johan Hedberga664b5b2011-02-19 12:06:02 -03002954 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002955
2956 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002957}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002958
2959int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2960{
2961 struct mgmt_ev_connect_failed ev;
2962
Johan Hedberg17d5c042011-01-22 06:09:08 +02002963 bacpy(&ev.bdaddr, bdaddr);
2964 ev.status = status;
2965
Szymon Janc4e51eae2011-02-25 19:05:48 +01002966 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002967}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002970{
2971 struct mgmt_ev_pin_code_request ev;
2972
Brian Gixa68668b2011-08-11 15:49:36 -07002973 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002974
Johan Hedberg980e1a52011-01-22 06:10:07 +02002975 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002976 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002977
Szymon Janc4e51eae2011-02-25 19:05:48 +01002978 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2979 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002980}
2981
2982int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2983{
2984 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002985 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002986 int err;
2987
2988 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2989 if (!cmd)
2990 return -ENOENT;
2991
Johan Hedbergac56fb12011-02-19 12:05:59 -03002992 bacpy(&rp.bdaddr, bdaddr);
2993 rp.status = status;
2994
Szymon Janc4e51eae2011-02-25 19:05:48 +01002995 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2996 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002997
Johan Hedberga664b5b2011-02-19 12:06:02 -03002998 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002999
3000 return err;
3001}
3002
3003int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3004{
3005 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003006 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003007 int err;
3008
3009 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
3010 if (!cmd)
3011 return -ENOENT;
3012
Johan Hedbergac56fb12011-02-19 12:05:59 -03003013 bacpy(&rp.bdaddr, bdaddr);
3014 rp.status = status;
3015
Szymon Janc4e51eae2011-02-25 19:05:48 +01003016 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
3017 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003018
Johan Hedberga664b5b2011-02-19 12:06:02 -03003019 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003020
3021 return err;
3022}
Johan Hedberga5c29682011-02-19 12:05:57 -03003023
Brian Gixa68668b2011-08-11 15:49:36 -07003024int mgmt_user_confirm_request(u16 index, u8 event,
3025 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03003026{
3027 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07003028 struct hci_conn *conn = NULL;
3029 struct hci_dev *hdev;
3030 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03003031
Brian Gixa68668b2011-08-11 15:49:36 -07003032 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03003033
Brian Gixa68668b2011-08-11 15:49:36 -07003034 hdev = hci_dev_get(index);
3035
Brian Gix64bd5302011-09-08 11:35:48 -07003036 if (!hdev)
3037 return -ENODEV;
3038
Brian Gix64bd5302011-09-08 11:35:48 -07003039 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003040
3041 ev.auto_confirm = 0;
3042
3043 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
3044 goto no_auto_confirm;
3045
3046 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
3047 rem_cap = conn->remote_cap;
3048 loc_mitm = conn->auth_type & 0x01;
3049 rem_mitm = conn->remote_auth & 0x01;
3050
Brian Gixdbf59292011-11-11 15:45:17 -08003051 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
3052 conn->auth_initiator && rem_cap == 0x03)
3053 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303054 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
3055 if (!loc_mitm && !rem_mitm)
3056 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07003057 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303058 }
Brian Gixa68668b2011-08-11 15:49:36 -07003059
Bhasker Neti2dc74942012-10-25 17:42:12 +05303060 /* Show bonding dialog if neither side requires no bonding */
3061 if ((conn->auth_type > 0x01) && (conn->remote_auth > 0x01)) {
3062 if (!loc_mitm && !rem_mitm)
3063 value = 0;
3064 goto no_auto_confirm;
3065 }
Brian Gixa68668b2011-08-11 15:49:36 -07003066
3067 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
3068 ev.auto_confirm = 1;
3069
3070no_auto_confirm:
3071 bacpy(&ev.bdaddr, bdaddr);
3072 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03003073 put_unaligned_le32(value, &ev.value);
3074
Brian Gix64bd5302011-09-08 11:35:48 -07003075 hci_dev_put(hdev);
3076
Brian Gixa68668b2011-08-11 15:49:36 -07003077 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
3078 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003079}
3080
Brian Gixa68668b2011-08-11 15:49:36 -07003081int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08003082{
3083 struct mgmt_ev_user_passkey_request ev;
3084
Johan Hedberga5c29682011-02-19 12:05:57 -03003085 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08003086
Johan Hedberga5c29682011-02-19 12:05:57 -03003087 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003088
Brian Gixa68668b2011-08-11 15:49:36 -07003089 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03003090 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003091}
3092
Johan Hedberga5c29682011-02-19 12:05:57 -03003093static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
3094 u8 opcode)
3095{
3096 struct pending_cmd *cmd;
3097 struct mgmt_rp_user_confirm_reply rp;
3098 int err;
3099
3100 cmd = mgmt_pending_find(opcode, index);
3101 if (!cmd)
3102 return -ENOENT;
3103
Johan Hedberga5c29682011-02-19 12:05:57 -03003104 bacpy(&rp.bdaddr, bdaddr);
3105 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003106 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003109
3110 return err;
3111}
3112
3113int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3114{
3115 return confirm_reply_complete(index, bdaddr, status,
3116 MGMT_OP_USER_CONFIRM_REPLY);
3117}
3118
Szymon Jancb8534e02011-03-01 16:55:34 +01003119int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003120{
3121 return confirm_reply_complete(index, bdaddr, status,
3122 MGMT_OP_USER_CONFIRM_NEG_REPLY);
3123}
Johan Hedberg2a611692011-02-19 12:06:00 -03003124
3125int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3126{
3127 struct mgmt_ev_auth_failed ev;
3128
Johan Hedberg2a611692011-02-19 12:06:00 -03003129 bacpy(&ev.bdaddr, bdaddr);
3130 ev.status = status;
3131
Szymon Janc4e51eae2011-02-25 19:05:48 +01003132 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003133}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003134
3135int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
3136{
3137 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003138 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003139 struct mgmt_cp_set_local_name ev;
3140 int err;
3141
3142 memset(&ev, 0, sizeof(ev));
3143 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3144
3145 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
3146 if (!cmd)
3147 goto send_event;
3148
3149 if (status) {
3150 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
3151 goto failed;
3152 }
3153
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003154 hdev = hci_dev_get(index);
3155 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003156 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003157 hci_dev_put(hdev);
3158 }
3159
Johan Hedbergb312b1612011-03-16 14:29:37 +02003160 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
3161 sizeof(ev));
3162 if (err < 0)
3163 goto failed;
3164
3165send_event:
3166 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
3167 cmd ? cmd->sk : NULL);
3168
3169failed:
3170 if (cmd)
3171 mgmt_pending_remove(cmd);
3172 return err;
3173}
Szymon Jancc35938b2011-03-22 13:12:21 +01003174
3175int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
3176 u8 status)
3177{
3178 struct pending_cmd *cmd;
3179 int err;
3180
3181 BT_DBG("hci%u status %u", index, status);
3182
3183 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
3184 if (!cmd)
3185 return -ENOENT;
3186
3187 if (status) {
3188 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3189 EIO);
3190 } else {
3191 struct mgmt_rp_read_local_oob_data rp;
3192
3193 memcpy(rp.hash, hash, sizeof(rp.hash));
3194 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3195
3196 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3197 &rp, sizeof(rp));
3198 }
3199
3200 mgmt_pending_remove(cmd);
3201
3202 return err;
3203}
Johan Hedberge17acd42011-03-30 23:57:16 +03003204
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003205void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
3206 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02003207{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003208 struct mgmt_ev_rssi_update ev;
3209 struct hci_conn *conn;
3210 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003211
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003212 if (status)
3213 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003214
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003215 hdev = hci_dev_get(index);
3216 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003217
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003218 if (!conn)
3219 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003220
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003221 BT_DBG("rssi_update_thresh_exceed : %d ",
3222 conn->rssi_update_thresh_exceed);
3223 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
3224 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003225
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003226 if (conn->rssi_update_thresh_exceed == 1) {
3227 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003228 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003229 memset(&ev, 0, sizeof(ev));
3230 bacpy(&ev.bdaddr, bdaddr);
3231 ev.rssi = rssi;
3232 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3233 sizeof(ev), NULL);
3234 } else {
3235 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3236 conn->rssi_update_interval,
3237 conn->rssi_update_thresh_exceed);
3238 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003239 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003240 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003241 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003242 memset(&ev, 0, sizeof(ev));
3243 bacpy(&ev.bdaddr, bdaddr);
3244 ev.rssi = rssi;
3245 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3246 sizeof(ev), NULL);
3247 } else {
3248 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3249 conn->rssi_update_interval,
3250 conn->rssi_update_thresh_exceed);
3251 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003252 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003253}
3254
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003255
Brian Gixa68668b2011-08-11 15:49:36 -07003256int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
3257 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03003258{
3259 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08003260 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003261 int err;
3262
Brian Gixa68668b2011-08-11 15:49:36 -07003263 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003264
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003265 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003266
Johan Hedberge17acd42011-03-30 23:57:16 +03003267 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03003268 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07003269 ev.type = type;
3270 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03003271
Brian Gixa68668b2011-08-11 15:49:36 -07003272 if (dev_class)
3273 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03003274
Brian Gixa68668b2011-08-11 15:49:36 -07003275 if (eir && eir_len)
3276 memcpy(ev.eir, eir, eir_len);
3277
3278 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3279
3280 if (err < 0)
3281 return err;
3282
Brian Gix568dde92012-01-11 16:18:04 -08003283 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003284
Brian Gix568dde92012-01-11 16:18:04 -08003285 if (!hdev)
3286 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003287
Brian Gix568dde92012-01-11 16:18:04 -08003288 if (hdev->disco_state == SCAN_IDLE)
3289 goto done;
3290
3291 hdev->disco_int_count++;
3292
3293 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3294 /* Inquiry scan for General Discovery LAP */
3295 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3296 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3297
3298 hdev->disco_int_phase *= 2;
3299 hdev->disco_int_count = 0;
3300 if (hdev->disco_state == SCAN_LE) {
3301 /* cancel LE scan */
3302 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3303 sizeof(le_cp), &le_cp);
3304 /* start BR scan */
3305 cp.num_rsp = (u8) hdev->disco_int_phase;
3306 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3307 sizeof(cp), &cp);
3308 hdev->disco_state = SCAN_BR;
3309 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003310 }
3311 }
3312
Brian Gix568dde92012-01-11 16:18:04 -08003313done:
3314 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003315 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003316}
Antti Julku5e762442011-08-25 16:48:02 +03003317
Brian Gixa68668b2011-08-11 15:49:36 -07003318
3319int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003320{
Johan Hedberga88a9652011-03-30 13:18:12 +03003321 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003322
Johan Hedberga88a9652011-03-30 13:18:12 +03003323 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003324
Johan Hedberga88a9652011-03-30 13:18:12 +03003325 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003326 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003327 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003328
Johan Hedberga88a9652011-03-30 13:18:12 +03003329 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003330}
3331
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303332int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003333{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303334 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003335
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303336 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003337
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303338 bacpy(&ev.bdaddr, bdaddr);
3339 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003340
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303341 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3342 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003343}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003344
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303345int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3346{
3347 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003348
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303349 memset(&ev, 0, sizeof(ev));
3350
3351 bacpy(&ev.bdaddr, bdaddr);
3352 memcpy(ev.dev_class, dev_class, 3);
3353
3354 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3355}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303356
3357int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3358 u16 sub_ver)
3359{
3360 struct mgmt_ev_remote_version ev;
3361
3362 memset(&ev, 0, sizeof(ev));
3363
3364 bacpy(&ev.bdaddr, bdaddr);
3365 ev.lmp_ver = ver;
3366 ev.manufacturer = mnf;
3367 ev.lmp_subver = sub_ver;
3368
3369 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3370}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003371
3372int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3373{
3374 struct mgmt_ev_remote_features ev;
3375
3376 memset(&ev, 0, sizeof(ev));
3377
3378 bacpy(&ev.bdaddr, bdaddr);
3379 memcpy(ev.features, features, sizeof(ev.features));
3380
3381 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3382 NULL);
3383}