blob: dc6281e68cd157ecabda877debe9e84612626075 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
Duy Truonge833aca2013-02-12 13:35:08 -08004 Copyright (c) 2011-2012 The Linux Foundation. All rights reserved.
Johan Hedberg03811012010-12-08 00:21:06 +02005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
24/* Bluetooth HCI Management interface */
25
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/interrupt.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040028#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020029#include <asm/unaligned.h>
30
31#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010039
Brian Gix568dde92012-01-11 16:18:04 -080040#define SCAN_IDLE 0x00
41#define SCAN_LE 0x01
42#define SCAN_BR 0x02
Johan Hedberg4b34ee782012-02-21 14:13:02 +020043
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044struct pending_cmd {
45 struct list_head list;
46 __u16 opcode;
47 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010048 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030050 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020051};
52
Mat Martineau8cd0df02011-08-23 16:23:36 -070053struct mgmt_pending_free_work {
54 struct work_struct work;
55 struct sock *sk;
Johan Hedbergca69b792011-11-11 18:10:00 +020056};
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058LIST_HEAD(cmd_list);
Johan Hedbergca69b792011-11-11 18:10:00 +020059
Szymon Janc4e51eae2011-02-25 19:05:48 +010060static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020061{
62 struct sk_buff *skb;
63 struct mgmt_hdr *hdr;
64 struct mgmt_ev_cmd_status *ev;
65
Szymon Janc34eb5252011-02-28 14:10:08 +010066 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020067
68 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
69 if (!skb)
70 return -ENOMEM;
71
72 hdr = (void *) skb_put(skb, sizeof(*hdr));
73
74 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010075 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076 hdr->len = cpu_to_le16(sizeof(*ev));
77
78 ev = (void *) skb_put(skb, sizeof(*ev));
79 ev->status = status;
80 put_unaligned_le16(cmd, &ev->opcode);
81
82 if (sock_queue_rcv_skb(sk, skb) < 0)
83 kfree_skb(skb);
84
85 return 0;
86}
87
Szymon Janc4e51eae2011-02-25 19:05:48 +010088static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
89 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020090{
91 struct sk_buff *skb;
92 struct mgmt_hdr *hdr;
93 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020094
95 BT_DBG("sock %p", sk);
96
Johan Hedberga38528f2011-01-22 06:46:43 +020097 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020098 if (!skb)
99 return -ENOMEM;
100
101 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200102
Johan Hedberg02d98122010-12-13 21:07:04 +0200103 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100104 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106
Johan Hedberga38528f2011-01-22 06:46:43 +0200107 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
108 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100109
110 if (rp)
111 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200112
113 if (sock_queue_rcv_skb(sk, skb) < 0)
114 kfree_skb(skb);
115
116 return 0;
117}
118
Johan Hedberga38528f2011-01-22 06:46:43 +0200119static int read_version(struct sock *sk)
120{
121 struct mgmt_rp_read_version rp;
122
123 BT_DBG("sock %p", sk);
124
125 rp.version = MGMT_VERSION;
126 put_unaligned_le16(MGMT_REVISION, &rp.revision);
127
Szymon Janc4e51eae2011-02-25 19:05:48 +0100128 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
129 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200130}
131
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132static int read_index_list(struct sock *sk)
133{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134 struct mgmt_rp_read_index_list *rp;
135 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200138 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139
140 BT_DBG("sock %p", sk);
141
142 read_lock(&hci_dev_list_lock);
143
144 count = 0;
145 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
147 if (d->dev_type != HCI_BREDR)
148 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Peter Krystad1fc44072011-08-30 15:38:12 -0700167 if (d->dev_type != HCI_BREDR)
168 continue;
169
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200170 set_bit(HCI_MGMT, &d->flags);
171
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172 if (test_bit(HCI_SETUP, &d->flags))
173 continue;
174
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200175 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700176 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200177 BT_DBG("Added hci%u", d->id);
178 }
179
180 read_unlock(&hci_dev_list_lock);
181
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
183 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200184
Johan Hedberga38528f2011-01-22 06:46:43 +0200185 kfree(rp);
186
187 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200188}
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200191{
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200201 hci_del_off_timer(hdev);
202
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800203 hci_dev_lock_bh(hdev);
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100204
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200205 set_bit(HCI_MGMT, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200207 memset(&rp, 0, sizeof(rp));
208
Johan Hedberga38528f2011-01-22 06:46:43 +0200209 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Johan Hedberga38528f2011-01-22 06:46:43 +0200211 rp.powered = test_bit(HCI_UP, &hdev->flags);
212 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
213 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
214 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200221 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222
Johan Hedberga38528f2011-01-22 06:46:43 +0200223 bacpy(&rp.bdaddr, &hdev->bdaddr);
224 memcpy(rp.features, hdev->features, 8);
225 memcpy(rp.dev_class, hdev->dev_class, 3);
226 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
227 rp.hci_ver = hdev->hci_ver;
228 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200230 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
231
Sunny 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
Archana Ramachandranc5ac78a2012-10-02 17:55:55 -07002113static int le_cancel_create_conn(struct sock *sk, u16 index,
2114 unsigned char *data, u16 len)
2115{
2116 struct mgmt_cp_le_cancel_create_conn *cp = (void *) data;
2117 struct hci_dev *hdev;
2118 int err = 0;
2119
2120 if (len != sizeof(*cp))
2121 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2122 EINVAL);
2123
2124 hdev = hci_dev_get(index);
2125
2126 if (!hdev)
2127 return cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2128 ENODEV);
2129
2130 hci_dev_lock_bh(hdev);
2131
2132 if (!test_bit(HCI_UP, &hdev->flags)) {
2133 err = cmd_status(sk, index, MGMT_OP_LE_CANCEL_CREATE_CONN,
2134 ENETDOWN);
2135 goto failed;
2136 }
2137
2138 hci_le_cancel_create_connect(hdev, &cp->bdaddr);
2139
2140failed:
2141 hci_dev_unlock_bh(hdev);
2142 hci_dev_put(hdev);
2143
2144return err;
2145}
2146
Johan Hedberg03811012010-12-08 00:21:06 +02002147static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
2148 u16 len)
2149{
2150 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
2151 struct hci_cp_write_local_name hci_cp;
2152 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01002153 struct pending_cmd *cmd;
2154 int err;
2155
Johan Hedberg03811012010-12-08 00:21:06 +02002156 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01002157
Johan Hedberg03811012010-12-08 00:21:06 +02002158 if (len != sizeof(*mgmt_cp))
2159 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01002160
Johan Hedberg03811012010-12-08 00:21:06 +02002161 hdev = hci_dev_get(index);
2162 if (!hdev)
2163 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
2164
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002165 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002166
2167 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
2168 if (!cmd) {
2169 err = -ENOMEM;
2170 goto failed;
2171 }
2172
2173 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2174 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2175 &hci_cp);
2176 if (err < 0)
2177 mgmt_pending_remove(cmd);
2178
2179failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002180 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002181 hci_dev_put(hdev);
2182
2183 return err;
2184}
2185
Brian Gixa68668b2011-08-11 15:49:36 -07002186static void discovery_rsp(struct pending_cmd *cmd, void *data)
2187{
2188 struct mgmt_mode ev;
2189
2190 BT_DBG("");
2191 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
2192 ev.val = 1;
2193 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
2194 } else {
2195 ev.val = 0;
2196 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
2197 NULL, 0);
2198 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08002199 struct hci_dev *hdev = hci_dev_get(cmd->index);
2200 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08002201 del_timer(&hdev->disco_le_timer);
2202 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08002203 hci_dev_put(hdev);
2204 }
Brian Gixa68668b2011-08-11 15:49:36 -07002205 }
2206 }
2207
2208 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
2209
2210 list_del(&cmd->list);
2211
2212 mgmt_pending_free(cmd);
2213}
2214
2215void mgmt_inquiry_started(u16 index)
2216{
2217 BT_DBG("");
2218 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
2219 discovery_rsp, NULL);
2220}
2221
2222void mgmt_inquiry_complete_evt(u16 index, u8 status)
2223{
2224 struct hci_dev *hdev;
2225 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08002226 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002227 int err = -1;
2228
Brian Gixa68668b2011-08-11 15:49:36 -07002229 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07002230
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302231 if (hdev)
2232 BT_DBG("disco_state: %d", hdev->disco_state);
2233
Brian Gixa68668b2011-08-11 15:49:36 -07002234 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07002235
2236 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2237 discovery_terminated, NULL);
2238
2239 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002240
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302241 hdev->disco_state = SCAN_IDLE;
2242
Brian Gix64bd5302011-09-08 11:35:48 -07002243 if (hdev)
2244 goto done;
2245 else
2246 return;
2247 }
Brian Gixa68668b2011-08-11 15:49:36 -07002248
Brian Gix568dde92012-01-11 16:18:04 -08002249 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002250 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2251 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002252 if (err >= 0) {
2253 mod_timer(&hdev->disco_le_timer, jiffies +
2254 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2255 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002256 } else
Brian Gix568dde92012-01-11 16:18:04 -08002257 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002258 }
2259
Brian Gix568dde92012-01-11 16:18:04 -08002260 if (hdev->disco_state == SCAN_IDLE)
2261 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2262
Brian Gixa68668b2011-08-11 15:49:36 -07002263 if (err < 0)
2264 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2265 discovery_terminated, NULL);
2266
Brian Gix64bd5302011-09-08 11:35:48 -07002267done:
Brian Gixa68668b2011-08-11 15:49:36 -07002268 hci_dev_put(hdev);
2269}
2270
Brian Gix568dde92012-01-11 16:18:04 -08002271void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002272{
Brian Gix568dde92012-01-11 16:18:04 -08002273 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002274 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002275 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002276
Brian Gix568dde92012-01-11 16:18:04 -08002277 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002278
Brian Gix568dde92012-01-11 16:18:04 -08002279 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002280
Brian Gix568dde92012-01-11 16:18:04 -08002281 if (!hdev)
2282 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002283
Brian Gix568dde92012-01-11 16:18:04 -08002284 hci_dev_lock_bh(hdev);
2285 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002286
Brian Gix568dde92012-01-11 16:18:04 -08002287 if (hdev->disco_state != SCAN_IDLE) {
2288 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002289
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302290 if (test_bit(HCI_UP, &hdev->flags)) {
2291 if (hdev->disco_state == SCAN_LE)
2292 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002293 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302294 else
2295 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2296 NULL);
2297 }
Brian Gix568dde92012-01-11 16:18:04 -08002298 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002299 }
Brian Gix568dde92012-01-11 16:18:04 -08002300
2301 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2302
2303 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2304 if (cmd)
2305 mgmt_pending_remove(cmd);
2306
2307 hci_dev_unlock_bh(hdev);
2308 hci_dev_put(hdev);
2309}
2310
2311void mgmt_disco_le_timeout(unsigned long data)
2312{
2313 struct hci_dev *hdev = (void *)data;
2314 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2315
2316 BT_DBG("hci%d", hdev->id);
2317
2318 hdev = hci_dev_get(hdev->id);
2319
2320 if (!hdev)
2321 return;
2322
2323 hci_dev_lock_bh(hdev);
2324
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302325 if (test_bit(HCI_UP, &hdev->flags)) {
2326 if (hdev->disco_state == SCAN_LE)
2327 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2328 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002329
2330 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302331 if (hdev->disco_state != SCAN_IDLE) {
2332 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2333 hdev->disco_int_phase *= 2;
2334 hdev->disco_int_count = 0;
2335 cp.num_rsp = (u8) hdev->disco_int_phase;
2336 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2337 hdev->disco_state = SCAN_BR;
2338 }
Brian Gix568dde92012-01-11 16:18:04 -08002339 }
2340
2341 hci_dev_unlock_bh(hdev);
2342 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002343}
2344
2345static int start_discovery(struct sock *sk, u16 index)
2346{
2347 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2348 struct hci_dev *hdev;
2349 struct pending_cmd *cmd;
2350 int err;
2351
2352 BT_DBG("");
2353
2354 hdev = hci_dev_get(index);
2355 if (!hdev)
2356 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2357
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302358 BT_DBG("disco_state: %d", hdev->disco_state);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002359 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002360
Brian Gix568dde92012-01-11 16:18:04 -08002361 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2362 err = -EBUSY;
2363 goto failed;
2364 }
2365
Brian Gixa68668b2011-08-11 15:49:36 -07002366 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2367 if (!cmd) {
2368 err = -ENOMEM;
2369 goto failed;
2370 }
2371
2372 /* If LE Capable, we will alternate between BR/EDR and LE */
2373 if (lmp_le_capable(hdev)) {
2374 struct hci_cp_le_set_scan_parameters le_cp;
2375
2376 /* Shorten BR scan params */
2377 cp.num_rsp = 1;
2378 cp.length /= 2;
2379
2380 /* Setup LE scan params */
2381 memset(&le_cp, 0, sizeof(le_cp));
2382 le_cp.type = 0x01; /* Active scanning */
2383 /* The recommended value for scan interval and window is
2384 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2385 le_cp.interval = cpu_to_le16(0x0012);
2386 le_cp.window = cpu_to_le16(0x0012);
2387 le_cp.own_bdaddr_type = 0; /* Public address */
2388 le_cp.filter = 0; /* Accept all adv packets */
2389
2390 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2391 sizeof(le_cp), &le_cp);
2392 }
2393
2394 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2395
Bhasker Neti09760742012-05-25 12:30:39 +05302396 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002397 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302398 hdev->disco_state = SCAN_IDLE;
2399 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002400 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2401 if (!cmd)
2402 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2403 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002404 hdev->disco_int_phase = 1;
2405 hdev->disco_int_count = 0;
2406 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002407 del_timer(&hdev->disco_le_timer);
2408 del_timer(&hdev->disco_timer);
2409 mod_timer(&hdev->disco_timer,
2410 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302411 } else
2412 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002413
2414failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002415 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002416 hci_dev_put(hdev);
2417
Brian Gix568dde92012-01-11 16:18:04 -08002418 if (err < 0)
2419 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2420
Brian Gixa68668b2011-08-11 15:49:36 -07002421 return err;
2422}
2423
2424static int stop_discovery(struct sock *sk, u16 index)
2425{
2426 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2427 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002428 struct hci_dev *hdev;
2429 struct pending_cmd *cmd = NULL;
2430 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002431 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002432
2433 BT_DBG("");
2434
2435 hdev = hci_dev_get(index);
2436 if (!hdev)
2437 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2438
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302439 BT_DBG("disco_state: %d", hdev->disco_state);
2440
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002441 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002442
Brian Gix568dde92012-01-11 16:18:04 -08002443 state = hdev->disco_state;
2444 hdev->disco_state = SCAN_IDLE;
2445 del_timer(&hdev->disco_le_timer);
2446 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002447
Brian Gix568dde92012-01-11 16:18:04 -08002448 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002449 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2450 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002451 if (err >= 0) {
2452 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2453 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002454
Brian Gix568dde92012-01-11 16:18:04 -08002455 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2456 NULL, 0);
2457 }
Bhasker Neti09760742012-05-25 12:30:39 +05302458 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002459 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002460
Brian Gix568dde92012-01-11 16:18:04 -08002461 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002462 if (err < 0 && cmd)
2463 mgmt_pending_remove(cmd);
2464
2465 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2466
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002467 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002468 hci_dev_put(hdev);
2469
2470 if (err < 0)
2471 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2472 else
2473 return err;
2474}
2475
Szymon Jancc35938b2011-03-22 13:12:21 +01002476static int read_local_oob_data(struct sock *sk, u16 index)
2477{
2478 struct hci_dev *hdev;
2479 struct pending_cmd *cmd;
2480 int err;
2481
2482 BT_DBG("hci%u", index);
2483
2484 hdev = hci_dev_get(index);
2485 if (!hdev)
2486 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2487 ENODEV);
2488
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002489 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002490
2491 if (!test_bit(HCI_UP, &hdev->flags)) {
2492 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2493 ENETDOWN);
2494 goto unlock;
2495 }
2496
2497 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2498 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2499 EOPNOTSUPP);
2500 goto unlock;
2501 }
2502
2503 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2504 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2505 goto unlock;
2506 }
2507
2508 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2509 if (!cmd) {
2510 err = -ENOMEM;
2511 goto unlock;
2512 }
2513
2514 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2515 if (err < 0)
2516 mgmt_pending_remove(cmd);
2517
2518unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002519 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002520 hci_dev_put(hdev);
2521
2522 return err;
2523}
2524
Szymon Janc2763eda2011-03-22 13:12:22 +01002525static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2526 u16 len)
2527{
2528 struct hci_dev *hdev;
2529 struct mgmt_cp_add_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_ADD_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_ADD_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_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2546 cp->randomizer);
2547 if (err < 0)
2548 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2549 else
2550 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2551 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002552
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002553 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002554 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002555
Szymon Janc2763eda2011-03-22 13:12:22 +01002556 return err;
2557}
2558
2559static int remove_remote_oob_data(struct sock *sk, u16 index,
2560 unsigned char *data, u16 len)
2561{
2562 struct hci_dev *hdev;
2563 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2564 int err;
2565
2566 BT_DBG("hci%u ", index);
2567
2568 if (len != sizeof(*cp))
2569 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2570 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002571
Szymon Janc2763eda2011-03-22 13:12:22 +01002572 hdev = hci_dev_get(index);
2573 if (!hdev)
2574 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2575 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002576
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002577 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002578
2579 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2580 if (err < 0)
2581 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2582 -err);
2583 else
2584 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2585 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002586
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002587 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002588 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002589
2590 return err;
2591}
2592
Johan Hedberg03811012010-12-08 00:21:06 +02002593int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2594{
2595 unsigned char *buf;
2596 struct mgmt_hdr *hdr;
2597 u16 opcode, index, len;
2598 int err;
2599
2600 BT_DBG("got %zu bytes", msglen);
2601
2602 if (msglen < sizeof(*hdr))
2603 return -EINVAL;
2604
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002605 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002606 if (!buf)
2607 return -ENOMEM;
2608
2609 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2610 err = -EFAULT;
2611 goto done;
2612 }
2613
2614 hdr = (struct mgmt_hdr *) buf;
2615 opcode = get_unaligned_le16(&hdr->opcode);
2616 index = get_unaligned_le16(&hdr->index);
2617 len = get_unaligned_le16(&hdr->len);
2618
2619 if (len != msglen - sizeof(*hdr)) {
2620 err = -EINVAL;
2621 goto done;
2622 }
2623
Brian Gixa68668b2011-08-11 15:49:36 -07002624 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002625 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002626 case MGMT_OP_READ_VERSION:
2627 err = read_version(sk);
2628 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002629 case MGMT_OP_READ_INDEX_LIST:
2630 err = read_index_list(sk);
2631 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002632 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002634 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002635 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002636 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002637 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002638 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002639 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002640 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002641 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2642 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2643 len);
2644 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002645 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002646 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002647 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002648 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002649 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002650 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002651 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002652 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002653 break;
2654 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002655 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002656 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002657 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002658 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002659 break;
2660 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002661 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002662 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002663 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002664 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002665 break;
2666 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002667 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002668 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002669 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002670 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002671 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002672 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002673 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002674 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002675 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002676 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002677 break;
2678 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002679 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002680 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002681 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002682 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002683 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002685 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002686 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002687 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002688 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002689 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002690 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2691 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002692 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002693 case MGMT_OP_SET_LOCAL_NAME:
2694 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2695 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002696 case MGMT_OP_START_DISCOVERY:
2697 err = start_discovery(sk, index);
2698 break;
2699 case MGMT_OP_STOP_DISCOVERY:
2700 err = stop_discovery(sk, index);
2701 break;
2702 case MGMT_OP_RESOLVE_NAME:
2703 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2704 break;
Ram Mohan Korukonda6d41bdf2012-11-27 16:13:54 +05302705 case MGMT_OP_CANCEL_RESOLVE_NAME:
2706 err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
2707 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002708 case MGMT_OP_SET_CONNECTION_PARAMS:
2709 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2710 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002711 case MGMT_OP_SET_RSSI_REPORTER:
2712 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2713 break;
2714 case MGMT_OP_UNSET_RSSI_REPORTER:
2715 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2716 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002717 case MGMT_OP_READ_LOCAL_OOB_DATA:
2718 err = read_local_oob_data(sk, index);
2719 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002720 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2721 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2722 break;
2723 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2724 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2725 len);
2726 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302727 case MGMT_OP_ENCRYPT_LINK:
2728 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2729 break;
Sunny Kapdi320598f2012-07-30 14:52:56 -07002730 case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
2731 err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
2732 len);
2733 break;
2734 case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
2735 err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
2736 len);
2737 break;
2738 case MGMT_OP_LE_CLEAR_WHITE_LIST:
2739 err = le_clear_white_list(sk, index);
2740 break;
2741 case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
2742 err = le_create_conn_white_list(sk, index);
2743 break;
2744 case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
2745 err = le_cancel_create_conn_white_list(sk, index);
2746 break;
Archana Ramachandranc5ac78a2012-10-02 17:55:55 -07002747 case MGMT_OP_LE_CANCEL_CREATE_CONN:
2748 err = le_cancel_create_conn(sk, index, buf + sizeof(*hdr), len);
2749 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002750 default:
2751 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002752 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002753 break;
2754 }
2755
Johan Hedberge41d8b42010-12-13 21:07:03 +02002756 if (err < 0)
2757 goto done;
2758
Johan Hedberg03811012010-12-08 00:21:06 +02002759 err = msglen;
2760
2761done:
2762 kfree(buf);
2763 return err;
2764}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002765
Johan Hedbergb24752f2011-11-03 14:40:33 +02002766static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2767{
2768 u8 *status = data;
2769
2770 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2771 mgmt_pending_remove(cmd);
2772}
2773
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002774int mgmt_index_added(u16 index)
2775{
Brian Gixa68668b2011-08-11 15:49:36 -07002776 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002777 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002778}
2779
2780int mgmt_index_removed(u16 index)
2781{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002782 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002783
Brian Gixa68668b2011-08-11 15:49:36 -07002784 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002785
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002786 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2787
Szymon Janc4e51eae2011-02-25 19:05:48 +01002788 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002789}
2790
Johan Hedberg73f22f62010-12-29 16:00:25 +02002791struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002792 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002793 struct sock *sk;
2794};
2795
Johan Hedberg72a734e2010-12-30 00:38:22 +02002796static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002797{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002798 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002799 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002800
Johan Hedberg72a734e2010-12-30 00:38:22 +02002801 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002802 return;
2803
Johan Hedberg053f0212011-01-26 13:07:10 +02002804 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002805
2806 list_del(&cmd->list);
2807
2808 if (match->sk == NULL) {
2809 match->sk = cmd->sk;
2810 sock_hold(match->sk);
2811 }
2812
2813 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002814}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002815
2816int mgmt_powered(u16 index, u8 powered)
2817{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002818 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002819 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002820 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002821
Brian Gixa68668b2011-08-11 15:49:36 -07002822 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002823
Johan Hedberg72a734e2010-12-30 00:38:22 +02002824 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002825
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002826 if (!powered) {
2827 u8 status = ENETDOWN;
2828 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002829 }
2830
Johan Hedberg72a734e2010-12-30 00:38:22 +02002831 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002832
Szymon Janc4e51eae2011-02-25 19:05:48 +01002833 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002834
2835 if (match.sk)
2836 sock_put(match.sk);
2837
2838 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002839}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002840
Johan Hedberg73f22f62010-12-29 16:00:25 +02002841int mgmt_discoverable(u16 index, u8 discoverable)
2842{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002843 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002844 struct cmd_lookup match = { discoverable, NULL };
2845 int ret;
2846
Szymon Jancb8534e02011-03-01 16:55:34 +01002847 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002848
Johan Hedberg73f22f62010-12-29 16:00:25 +02002849 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002850
Szymon Janc4e51eae2011-02-25 19:05:48 +01002851 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2852 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002853
Johan Hedberg73f22f62010-12-29 16:00:25 +02002854 if (match.sk)
2855 sock_put(match.sk);
2856
2857 return ret;
2858}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002859
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002860int mgmt_connectable(u16 index, u8 connectable)
2861{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002862 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002863 struct cmd_lookup match = { connectable, NULL };
2864 int ret;
2865
Johan Hedberg72a734e2010-12-30 00:38:22 +02002866 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002867
Johan Hedberg03811012010-12-08 00:21:06 +02002868 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002869
Szymon Janc4e51eae2011-02-25 19:05:48 +01002870 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002871
2872 if (match.sk)
2873 sock_put(match.sk);
2874
2875 return ret;
2876}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002877
Brian Gixa68668b2011-08-11 15:49:36 -07002878int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002879{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002880 struct mgmt_ev_new_key *ev;
2881 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002882
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002883 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2884 ev = kzalloc(total, GFP_ATOMIC);
2885 if (!ev)
2886 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002887
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002888 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002889 ev->key.addr_type = key->addr_type;
2890 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002891 memcpy(ev->key.val, key->val, 16);
2892 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002893 ev->key.auth = key->auth;
2894 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002895 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002896
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002897 memcpy(ev->key.data, key->data, key->dlen);
2898
2899 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2900
2901 kfree(ev);
2902
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002903 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002904}
2905
Brian Gix2e2f50d2011-09-13 12:36:04 -07002906int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002907{
Johan Hedbergf7520542011-01-20 12:34:39 +02002908 struct mgmt_ev_connected ev;
Sunny Kapdi320598f2012-07-30 14:52:56 -07002909 struct pending_cmd *cmd;
2910 struct hci_dev *hdev;
2911
2912 BT_DBG("hci%u", index);
2913
2914 hdev = hci_dev_get(index);
2915
2916 if (!hdev)
2917 return -ENODEV;
Johan Hedbergca69b792011-11-11 18:10:00 +02002918
Johan Hedbergf7520542011-01-20 12:34:39 +02002919 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002920 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002921
Sunny Kapdi320598f2012-07-30 14:52:56 -07002922 cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
2923 if (cmd) {
2924 BT_ERR("mgmt_connected remove mgmt pending white_list");
2925 mgmt_pending_remove(cmd);
2926 }
2927
Szymon Janc4e51eae2011-02-25 19:05:48 +01002928 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002929}
2930
Sunny Kapdia42b5022012-07-05 22:48:31 -07002931int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
2932 u16 latency, u16 timeout)
2933{
2934 struct mgmt_ev_le_conn_params ev;
2935
2936 bacpy(&ev.bdaddr, bdaddr);
2937 ev.interval = interval;
2938 ev.latency = latency;
2939 ev.timeout = timeout;
2940
2941 return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
2942 NULL);
2943}
2944
Johan Hedberg8962ee72011-01-20 12:40:27 +02002945static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2946{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002947 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002948 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002949 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002950
Johan Hedberga38528f2011-01-22 06:46:43 +02002951 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002952
Szymon Janc4e51eae2011-02-25 19:05:48 +01002953 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002954
2955 *sk = cmd->sk;
2956 sock_hold(*sk);
2957
Johan Hedberga664b5b2011-02-19 12:06:02 -03002958 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002959}
2960
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002961int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002962{
Johan Hedbergf7520542011-01-20 12:34:39 +02002963 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002964 struct sock *sk = NULL;
2965 int err;
2966
Johan Hedbergf7520542011-01-20 12:34:39 +02002967 bacpy(&ev.bdaddr, bdaddr);
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002968 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02002969
Szymon Janc4e51eae2011-02-25 19:05:48 +01002970 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002971
2972 if (sk)
2973 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002974
Archana Ramachandranb2f194d2012-08-14 12:03:01 -07002975 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
2976
Johan Hedberg8962ee72011-01-20 12:40:27 +02002977 return err;
2978}
2979
2980int mgmt_disconnect_failed(u16 index)
2981{
2982 struct pending_cmd *cmd;
2983 int err;
2984
2985 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2986 if (!cmd)
2987 return -ENOENT;
2988
Szymon Janc4e51eae2011-02-25 19:05:48 +01002989 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002990
Johan Hedberga664b5b2011-02-19 12:06:02 -03002991 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002992
2993 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002994}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002995
2996int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2997{
2998 struct mgmt_ev_connect_failed ev;
2999
Johan Hedberg17d5c042011-01-22 06:09:08 +02003000 bacpy(&ev.bdaddr, bdaddr);
3001 ev.status = status;
3002
Szymon Janc4e51eae2011-02-25 19:05:48 +01003003 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003004}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003007{
3008 struct mgmt_ev_pin_code_request ev;
3009
Brian Gixa68668b2011-08-11 15:49:36 -07003010 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003011
Johan Hedberg980e1a52011-01-22 06:10:07 +02003012 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003013 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003014
Szymon Janc4e51eae2011-02-25 19:05:48 +01003015 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
3016 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003017}
3018
3019int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3020{
3021 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003022 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003023 int err;
3024
3025 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
3026 if (!cmd)
3027 return -ENOENT;
3028
Johan Hedbergac56fb12011-02-19 12:05:59 -03003029 bacpy(&rp.bdaddr, bdaddr);
3030 rp.status = status;
3031
Szymon Janc4e51eae2011-02-25 19:05:48 +01003032 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
3033 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003034
Johan Hedberga664b5b2011-02-19 12:06:02 -03003035 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003036
3037 return err;
3038}
3039
3040int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3041{
3042 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003043 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003044 int err;
3045
3046 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
3047 if (!cmd)
3048 return -ENOENT;
3049
Johan Hedbergac56fb12011-02-19 12:05:59 -03003050 bacpy(&rp.bdaddr, bdaddr);
3051 rp.status = status;
3052
Szymon Janc4e51eae2011-02-25 19:05:48 +01003053 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
3054 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003055
Johan Hedberga664b5b2011-02-19 12:06:02 -03003056 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003057
3058 return err;
3059}
Johan Hedberga5c29682011-02-19 12:05:57 -03003060
Brian Gixa68668b2011-08-11 15:49:36 -07003061int mgmt_user_confirm_request(u16 index, u8 event,
3062 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03003063{
3064 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07003065 struct hci_conn *conn = NULL;
3066 struct hci_dev *hdev;
3067 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03003068
Brian Gixa68668b2011-08-11 15:49:36 -07003069 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03003070
Brian Gixa68668b2011-08-11 15:49:36 -07003071 hdev = hci_dev_get(index);
3072
Brian Gix64bd5302011-09-08 11:35:48 -07003073 if (!hdev)
3074 return -ENODEV;
3075
Brian Gix64bd5302011-09-08 11:35:48 -07003076 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003077
3078 ev.auto_confirm = 0;
3079
3080 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
3081 goto no_auto_confirm;
3082
3083 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
3084 rem_cap = conn->remote_cap;
3085 loc_mitm = conn->auth_type & 0x01;
3086 rem_mitm = conn->remote_auth & 0x01;
3087
Brian Gixdbf59292011-11-11 15:45:17 -08003088 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
3089 conn->auth_initiator && rem_cap == 0x03)
3090 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303091 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
3092 if (!loc_mitm && !rem_mitm)
3093 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07003094 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303095 }
Brian Gixa68668b2011-08-11 15:49:36 -07003096
Bhasker Neti2dc74942012-10-25 17:42:12 +05303097 /* Show bonding dialog if neither side requires no bonding */
3098 if ((conn->auth_type > 0x01) && (conn->remote_auth > 0x01)) {
3099 if (!loc_mitm && !rem_mitm)
3100 value = 0;
3101 goto no_auto_confirm;
3102 }
Brian Gixa68668b2011-08-11 15:49:36 -07003103
3104 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
3105 ev.auto_confirm = 1;
3106
3107no_auto_confirm:
3108 bacpy(&ev.bdaddr, bdaddr);
3109 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03003110 put_unaligned_le32(value, &ev.value);
3111
Brian Gix64bd5302011-09-08 11:35:48 -07003112 hci_dev_put(hdev);
3113
Brian Gixa68668b2011-08-11 15:49:36 -07003114 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
3115 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003116}
3117
Brian Gixa68668b2011-08-11 15:49:36 -07003118int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08003119{
3120 struct mgmt_ev_user_passkey_request ev;
3121
Johan Hedberga5c29682011-02-19 12:05:57 -03003122 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08003123
Johan Hedberga5c29682011-02-19 12:05:57 -03003124 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003125
Brian Gixa68668b2011-08-11 15:49:36 -07003126 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03003127 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003128}
3129
Johan Hedberga5c29682011-02-19 12:05:57 -03003130static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
3131 u8 opcode)
3132{
3133 struct pending_cmd *cmd;
3134 struct mgmt_rp_user_confirm_reply rp;
3135 int err;
3136
3137 cmd = mgmt_pending_find(opcode, index);
3138 if (!cmd)
3139 return -ENOENT;
3140
Johan Hedberga5c29682011-02-19 12:05:57 -03003141 bacpy(&rp.bdaddr, bdaddr);
3142 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003143 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003144
Johan Hedberga664b5b2011-02-19 12:06:02 -03003145 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003146
3147 return err;
3148}
3149
3150int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3151{
3152 return confirm_reply_complete(index, bdaddr, status,
3153 MGMT_OP_USER_CONFIRM_REPLY);
3154}
3155
Szymon Jancb8534e02011-03-01 16:55:34 +01003156int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003157{
3158 return confirm_reply_complete(index, bdaddr, status,
3159 MGMT_OP_USER_CONFIRM_NEG_REPLY);
3160}
Johan Hedberg2a611692011-02-19 12:06:00 -03003161
3162int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3163{
3164 struct mgmt_ev_auth_failed ev;
3165
Johan Hedberg2a611692011-02-19 12:06:00 -03003166 bacpy(&ev.bdaddr, bdaddr);
3167 ev.status = status;
3168
Szymon Janc4e51eae2011-02-25 19:05:48 +01003169 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003170}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003171
3172int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
3173{
3174 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003175 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003176 struct mgmt_cp_set_local_name ev;
3177 int err;
3178
3179 memset(&ev, 0, sizeof(ev));
3180 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3181
3182 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
3183 if (!cmd)
3184 goto send_event;
3185
3186 if (status) {
3187 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
3188 goto failed;
3189 }
3190
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003191 hdev = hci_dev_get(index);
3192 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003193 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003194 hci_dev_put(hdev);
3195 }
3196
Johan Hedbergb312b1612011-03-16 14:29:37 +02003197 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
3198 sizeof(ev));
3199 if (err < 0)
3200 goto failed;
3201
3202send_event:
3203 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
3204 cmd ? cmd->sk : NULL);
3205
3206failed:
3207 if (cmd)
3208 mgmt_pending_remove(cmd);
3209 return err;
3210}
Szymon Jancc35938b2011-03-22 13:12:21 +01003211
3212int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
3213 u8 status)
3214{
3215 struct pending_cmd *cmd;
3216 int err;
3217
3218 BT_DBG("hci%u status %u", index, status);
3219
3220 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
3221 if (!cmd)
3222 return -ENOENT;
3223
3224 if (status) {
3225 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3226 EIO);
3227 } else {
3228 struct mgmt_rp_read_local_oob_data rp;
3229
3230 memcpy(rp.hash, hash, sizeof(rp.hash));
3231 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3232
3233 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3234 &rp, sizeof(rp));
3235 }
3236
3237 mgmt_pending_remove(cmd);
3238
3239 return err;
3240}
Johan Hedberge17acd42011-03-30 23:57:16 +03003241
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003242void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
3243 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02003244{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003245 struct mgmt_ev_rssi_update ev;
3246 struct hci_conn *conn;
3247 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003248
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003249 if (status)
3250 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003251
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003252 hdev = hci_dev_get(index);
3253 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003254
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003255 if (!conn)
3256 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003257
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003258 BT_DBG("rssi_update_thresh_exceed : %d ",
3259 conn->rssi_update_thresh_exceed);
3260 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
3261 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003262
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003263 if (conn->rssi_update_thresh_exceed == 1) {
3264 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003265 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003266 memset(&ev, 0, sizeof(ev));
3267 bacpy(&ev.bdaddr, bdaddr);
3268 ev.rssi = rssi;
3269 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3270 sizeof(ev), NULL);
3271 } else {
3272 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3273 conn->rssi_update_interval,
3274 conn->rssi_update_thresh_exceed);
3275 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003276 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003277 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003278 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003279 memset(&ev, 0, sizeof(ev));
3280 bacpy(&ev.bdaddr, bdaddr);
3281 ev.rssi = rssi;
3282 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3283 sizeof(ev), NULL);
3284 } else {
3285 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3286 conn->rssi_update_interval,
3287 conn->rssi_update_thresh_exceed);
3288 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003289 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003290}
3291
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003292
Brian Gixa68668b2011-08-11 15:49:36 -07003293int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
3294 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03003295{
3296 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08003297 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003298 int err;
3299
Brian Gixa68668b2011-08-11 15:49:36 -07003300 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003301
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003302 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003303
Johan Hedberge17acd42011-03-30 23:57:16 +03003304 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03003305 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07003306 ev.type = type;
3307 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03003308
Brian Gixa68668b2011-08-11 15:49:36 -07003309 if (dev_class)
3310 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03003311
Brian Gixa68668b2011-08-11 15:49:36 -07003312 if (eir && eir_len)
3313 memcpy(ev.eir, eir, eir_len);
3314
3315 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3316
3317 if (err < 0)
3318 return err;
3319
Brian Gix568dde92012-01-11 16:18:04 -08003320 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003321
Brian Gix568dde92012-01-11 16:18:04 -08003322 if (!hdev)
3323 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003324
Brian Gix568dde92012-01-11 16:18:04 -08003325 if (hdev->disco_state == SCAN_IDLE)
3326 goto done;
3327
3328 hdev->disco_int_count++;
3329
3330 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3331 /* Inquiry scan for General Discovery LAP */
3332 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3333 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3334
3335 hdev->disco_int_phase *= 2;
3336 hdev->disco_int_count = 0;
3337 if (hdev->disco_state == SCAN_LE) {
3338 /* cancel LE scan */
3339 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3340 sizeof(le_cp), &le_cp);
3341 /* start BR scan */
3342 cp.num_rsp = (u8) hdev->disco_int_phase;
3343 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3344 sizeof(cp), &cp);
3345 hdev->disco_state = SCAN_BR;
3346 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003347 }
3348 }
3349
Brian Gix568dde92012-01-11 16:18:04 -08003350done:
3351 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003352 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003353}
Antti Julku5e762442011-08-25 16:48:02 +03003354
Brian Gixa68668b2011-08-11 15:49:36 -07003355
3356int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003357{
Johan Hedberga88a9652011-03-30 13:18:12 +03003358 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003359
Johan Hedberga88a9652011-03-30 13:18:12 +03003360 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003361
Johan Hedberga88a9652011-03-30 13:18:12 +03003362 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003363 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003364 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003365
Johan Hedberga88a9652011-03-30 13:18:12 +03003366 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003367}
3368
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303369int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003370{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303371 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003372
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303373 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003374
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303375 bacpy(&ev.bdaddr, bdaddr);
3376 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003377
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303378 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3379 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003380}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003381
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303382int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3383{
3384 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003385
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303386 memset(&ev, 0, sizeof(ev));
3387
3388 bacpy(&ev.bdaddr, bdaddr);
3389 memcpy(ev.dev_class, dev_class, 3);
3390
3391 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3392}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303393
3394int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3395 u16 sub_ver)
3396{
3397 struct mgmt_ev_remote_version ev;
3398
3399 memset(&ev, 0, sizeof(ev));
3400
3401 bacpy(&ev.bdaddr, bdaddr);
3402 ev.lmp_ver = ver;
3403 ev.manufacturer = mnf;
3404 ev.lmp_subver = sub_ver;
3405
3406 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3407}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003408
3409int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3410{
3411 struct mgmt_ev_remote_features ev;
3412
3413 memset(&ev, 0, sizeof(ev));
3414
3415 bacpy(&ev.bdaddr, bdaddr);
3416 memcpy(ev.features, features, sizeof(ev.features));
3417
3418 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3419 NULL);
3420}