blob: d7deaafb15a0be904918964c4e5dc816b0201683 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
Brian Gix568dde92012-01-11 16:18:04 -08004 Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
Johan Hedberg03811012010-12-08 00:21:06 +02005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
24/* Bluetooth HCI Management interface */
25
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/interrupt.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040028#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020029#include <asm/unaligned.h>
30
31#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070033#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010039
Brian Gix568dde92012-01-11 16:18:04 -080040#define SCAN_IDLE 0x00
41#define SCAN_LE 0x01
42#define SCAN_BR 0x02
Johan Hedberg4b34ee782012-02-21 14:13:02 +020043
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044struct pending_cmd {
45 struct list_head list;
46 __u16 opcode;
47 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010048 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030050 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020051};
52
Mat Martineau8cd0df02011-08-23 16:23:36 -070053struct mgmt_pending_free_work {
54 struct work_struct work;
55 struct sock *sk;
Johan Hedbergca69b792011-11-11 18:10:00 +020056};
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058LIST_HEAD(cmd_list);
Johan Hedbergca69b792011-11-11 18:10:00 +020059
Szymon Janc4e51eae2011-02-25 19:05:48 +010060static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020061{
62 struct sk_buff *skb;
63 struct mgmt_hdr *hdr;
64 struct mgmt_ev_cmd_status *ev;
65
Szymon Janc34eb5252011-02-28 14:10:08 +010066 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020067
68 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
69 if (!skb)
70 return -ENOMEM;
71
72 hdr = (void *) skb_put(skb, sizeof(*hdr));
73
74 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010075 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076 hdr->len = cpu_to_le16(sizeof(*ev));
77
78 ev = (void *) skb_put(skb, sizeof(*ev));
79 ev->status = status;
80 put_unaligned_le16(cmd, &ev->opcode);
81
82 if (sock_queue_rcv_skb(sk, skb) < 0)
83 kfree_skb(skb);
84
85 return 0;
86}
87
Szymon Janc4e51eae2011-02-25 19:05:48 +010088static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
89 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020090{
91 struct sk_buff *skb;
92 struct mgmt_hdr *hdr;
93 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020094
95 BT_DBG("sock %p", sk);
96
Johan Hedberga38528f2011-01-22 06:46:43 +020097 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020098 if (!skb)
99 return -ENOMEM;
100
101 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200102
Johan Hedberg02d98122010-12-13 21:07:04 +0200103 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100104 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106
Johan Hedberga38528f2011-01-22 06:46:43 +0200107 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
108 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100109
110 if (rp)
111 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200112
113 if (sock_queue_rcv_skb(sk, skb) < 0)
114 kfree_skb(skb);
115
116 return 0;
117}
118
Johan Hedberga38528f2011-01-22 06:46:43 +0200119static int read_version(struct sock *sk)
120{
121 struct mgmt_rp_read_version rp;
122
123 BT_DBG("sock %p", sk);
124
125 rp.version = MGMT_VERSION;
126 put_unaligned_le16(MGMT_REVISION, &rp.revision);
127
Szymon Janc4e51eae2011-02-25 19:05:48 +0100128 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
129 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200130}
131
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132static int read_index_list(struct sock *sk)
133{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200134 struct mgmt_rp_read_index_list *rp;
135 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200138 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139
140 BT_DBG("sock %p", sk);
141
142 read_lock(&hci_dev_list_lock);
143
144 count = 0;
145 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
147 if (d->dev_type != HCI_BREDR)
148 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Peter Krystad1fc44072011-08-30 15:38:12 -0700167 if (d->dev_type != HCI_BREDR)
168 continue;
169
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200170 set_bit(HCI_MGMT, &d->flags);
171
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172 if (test_bit(HCI_SETUP, &d->flags))
173 continue;
174
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200175 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700176 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200177 BT_DBG("Added hci%u", d->id);
178 }
179
180 read_unlock(&hci_dev_list_lock);
181
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
183 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200184
Johan Hedberga38528f2011-01-22 06:46:43 +0200185 kfree(rp);
186
187 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200188}
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200191{
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200201 hci_del_off_timer(hdev);
202
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800203 hci_dev_lock_bh(hdev);
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100204
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200205 set_bit(HCI_MGMT, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200207 memset(&rp, 0, sizeof(rp));
208
Johan Hedberga38528f2011-01-22 06:46:43 +0200209 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Johan Hedberga38528f2011-01-22 06:46:43 +0200211 rp.powered = test_bit(HCI_UP, &hdev->flags);
212 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
213 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
214 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200221 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222
Johan Hedberga38528f2011-01-22 06:46:43 +0200223 bacpy(&rp.bdaddr, &hdev->bdaddr);
224 memcpy(rp.features, hdev->features, 8);
225 memcpy(rp.dev_class, hdev->dev_class, 3);
226 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
227 rp.hci_ver = hdev->hci_ver;
228 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200230 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
231
Sunny Kapdi93bef892012-07-30 14:52:56 -0700232 rp.le_white_list_size = hdev->le_white_list_size;
233
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800234 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200238}
Johan Hedberg03811012010-12-08 00:21:06 +0200239
Mat Martineau8cd0df02011-08-23 16:23:36 -0700240static void mgmt_pending_free_worker(struct work_struct *work)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200241{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700242 struct mgmt_pending_free_work *free_work =
243 container_of(work, struct mgmt_pending_free_work, work);
Johan Hedberg03811012010-12-08 00:21:06 +0200244
Mat Martineau8cd0df02011-08-23 16:23:36 -0700245 BT_DBG("sk %p", free_work->sk);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100246
Mat Martineau8cd0df02011-08-23 16:23:36 -0700247 sock_put(free_work->sk);
248 kfree(free_work);
Johan Hedbergc542a062011-01-26 13:11:03 +0200249}
250
Johan Hedberg03811012010-12-08 00:21:06 +0200251static void mgmt_pending_free(struct pending_cmd *cmd)
252{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700253 struct mgmt_pending_free_work *free_work;
254 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700255
Mat Martineau8cd0df02011-08-23 16:23:36 -0700256 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
257
Johan Hedberg03811012010-12-08 00:21:06 +0200258 kfree(cmd->param);
259 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700260
261 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
262 if (free_work) {
263 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
264 free_work->sk = sk;
265
266 if (!schedule_work(&free_work->work))
267 kfree(free_work);
268 }
Johan Hedberg03811012010-12-08 00:21:06 +0200269}
270
271static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
272 u16 index, void *data, u16 len)
273{
274 struct pending_cmd *cmd;
275
Brian Gixa68668b2011-08-11 15:49:36 -0700276 BT_DBG("%d", opcode);
277
Johan Hedberg03811012010-12-08 00:21:06 +0200278 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
279 if (!cmd)
280 return NULL;
281
282 cmd->opcode = opcode;
283 cmd->index = index;
284
285 cmd->param = kmalloc(len, GFP_ATOMIC);
286 if (!cmd->param) {
287 kfree(cmd);
288 return NULL;
289 }
290
291 if (data)
292 memcpy(cmd->param, data, len);
293
294 cmd->sk = sk;
295 sock_hold(sk);
296
297 list_add(&cmd->list, &cmd_list);
298
299 return cmd;
300}
301
302static void mgmt_pending_foreach(u16 opcode, int index,
303 void (*cb)(struct pending_cmd *cmd, void *data),
304 void *data)
Johan Hedberge41d8b42010-12-13 21:07:03 +0200305{
306 struct list_head *p, *n;
Johan Hedberg03811012010-12-08 00:21:06 +0200307
Brian Gixa68668b2011-08-11 15:49:36 -0700308 BT_DBG(" %d", opcode);
309
Johan Hedberg03811012010-12-08 00:21:06 +0200310 list_for_each_safe(p, n, &cmd_list) {
311 struct pending_cmd *cmd;
312
313 cmd = list_entry(p, struct pending_cmd, list);
314
Johan Hedberg931bc4e2011-11-03 14:40:33 +0200315 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedberg03811012010-12-08 00:21:06 +0200316 continue;
317
318 if (index >= 0 && cmd->index != index)
319 continue;
320
321 cb(cmd, data);
322 }
323}
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324
325static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
326{
327 struct list_head *p;
328
Brian Gixa68668b2011-08-11 15:49:36 -0700329 BT_DBG(" %d", opcode);
330
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331 list_for_each(p, &cmd_list) {
332 struct pending_cmd *cmd;
333
334 cmd = list_entry(p, struct pending_cmd, list);
335
336 if (cmd->opcode != opcode)
337 continue;
338
339 if (index >= 0 && cmd->index != index)
340 continue;
341
342 return cmd;
343 }
344
345 return NULL;
346}
347
348static void mgmt_pending_remove(struct pending_cmd *cmd)
349{
Brian Gixa68668b2011-08-11 15:49:36 -0700350 BT_DBG(" %d", cmd->opcode);
351
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352 list_del(&cmd->list);
353 mgmt_pending_free(cmd);
354}
355
356static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
357{
358 struct mgmt_mode *cp;
359 struct hci_dev *hdev;
360 struct pending_cmd *cmd;
361 int err, up;
362
363 cp = (void *) data;
364
365 BT_DBG("request for hci%u", index);
366
367 if (len != sizeof(*cp))
368 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
369
370 hdev = hci_dev_get(index);
371 if (!hdev)
372 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
373
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800374 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375
376 up = test_bit(HCI_UP, &hdev->flags);
377 if ((cp->val && up) || (!cp->val && !up)) {
378 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
379 goto failed;
380 }
381
382 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
383 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
384 goto failed;
385 }
386
387 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
388 if (!cmd) {
389 err = -ENOMEM;
390 goto failed;
391 }
392
393 if (cp->val)
394 queue_work(hdev->workqueue, &hdev->power_on);
395 else
396 queue_work(hdev->workqueue, &hdev->power_off);
397
398 err = 0;
399
400failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800401 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200402 hci_dev_put(hdev);
403 return err;
404}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200405
Brian Gix8a7f1642011-10-17 17:39:46 -0700406static u8 get_service_classes(struct hci_dev *hdev)
407{
408 struct list_head *p;
409 u8 val = 0;
410
411 list_for_each(p, &hdev->uuids) {
412 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
413
414 val |= uuid->svc_hint;
415 }
416
417 return val;
418}
419
420static int update_class(struct hci_dev *hdev)
421{
422 u8 cod[3];
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530423 int err = 0;
Brian Gix8a7f1642011-10-17 17:39:46 -0700424
425 BT_DBG("%s", hdev->name);
426
427 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
428 return 0;
429
430 cod[0] = hdev->minor_class;
431 cod[1] = hdev->major_class;
432 cod[2] = get_service_classes(hdev);
433
434 if (memcmp(cod, hdev->dev_class, 3) == 0)
435 return 0;
436
Srinivas Krovvidi58562d82012-06-25 16:46:56 +0530437 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
438
439 if (err == 0)
440 memcpy(hdev->dev_class, cod, 3);
441
442 return err;
Brian Gix8a7f1642011-10-17 17:39:46 -0700443}
444
445static int set_limited_discoverable(struct sock *sk, u16 index,
446 unsigned char *data, u16 len)
447{
448 struct mgmt_mode *cp;
449 struct hci_dev *hdev;
450 struct pending_cmd *cmd;
451 struct hci_cp_write_current_iac_lap dcp;
452 int update_cod;
453 int err = 0;
454 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
455 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
456
457 cp = (void *) data;
458
459 BT_DBG("hci%u discoverable: %d", index, cp->val);
460
461 if (!cp || len != sizeof(*cp))
462 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
463 EINVAL);
464
465 hdev = hci_dev_get(index);
466 if (!hdev)
467 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
468 ENODEV);
469
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800470 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700471
472 if (!test_bit(HCI_UP, &hdev->flags)) {
473 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
474 ENETDOWN);
475 goto failed;
476 }
477
478 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
479 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
480 EBUSY);
481 goto failed;
482 }
483
484 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
485 test_bit(HCI_PSCAN, &hdev->flags)) {
486 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
487 EALREADY);
488 goto failed;
489 }
490
491 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
492 len);
493 if (!cmd) {
494 err = -ENOMEM;
495 goto failed;
496 }
497
498 memset(&dcp, 0, sizeof(dcp));
499 dcp.num_current_iac = cp->val ? 2 : 1;
500 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
501 update_cod = 1;
502
503 if (cp->val) {
504 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
505 update_cod = 0;
506 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
507 } else {
508 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
509 update_cod = 0;
510 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
511 }
512
513 if (update_cod)
514 err = update_class(hdev);
515
516 if (err >= 0)
517 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
518 sizeof(dcp), &dcp);
519
520 if (err < 0)
521 mgmt_pending_remove(cmd);
522
523failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800524 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700525 hci_dev_put(hdev);
526
527 return err;
528}
529
Johan Hedberg73f22f62010-12-29 16:00:25 +0200530static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
531 u16 len)
532{
533 struct mgmt_mode *cp;
534 struct hci_dev *hdev;
535 struct pending_cmd *cmd;
536 u8 scan;
537 int err;
538
539 cp = (void *) data;
540
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200541 BT_DBG("request for hci%u", index);
542
Johan Hedberg72a734e2010-12-30 00:38:22 +0200543 if (len != sizeof(*cp))
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200544 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
545
546 hdev = hci_dev_get(index);
547 if (!hdev)
548 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
549
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800550 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200551
552 if (!test_bit(HCI_UP, &hdev->flags)) {
553 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
554 goto failed;
555 }
556
557 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
558 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
559 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200560 goto failed;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200561 }
562
563 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
564 test_bit(HCI_PSCAN, &hdev->flags)) {
565 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
566 goto failed;
567 }
568
569 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
570 if (!cmd) {
571 err = -ENOMEM;
572 goto failed;
573 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200574
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200575 scan = SCAN_PAGE;
576
577 if (cp->val)
578 scan |= SCAN_INQUIRY;
579
580 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
581 if (err < 0)
582 mgmt_pending_remove(cmd);
583
584failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800585 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200586 hci_dev_put(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200587
588 return err;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200589}
Johan Hedberg73f22f62010-12-29 16:00:25 +0200590
591static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
592 u16 len)
593{
594 struct mgmt_mode *cp;
595 struct hci_dev *hdev;
596 struct pending_cmd *cmd;
597 u8 scan;
598 int err;
599
600 cp = (void *) data;
601
602 BT_DBG("request for hci%u", index);
603
604 if (len != sizeof(*cp))
605 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
606
607 hdev = hci_dev_get(index);
608 if (!hdev)
609 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
610
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800611 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200612
Johan Hedberg73f22f62010-12-29 16:00:25 +0200613 if (!test_bit(HCI_UP, &hdev->flags)) {
614 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
615 goto failed;
616 }
Johan Hedberg72a734e2010-12-30 00:38:22 +0200617
Johan Hedberg73f22f62010-12-29 16:00:25 +0200618 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
619 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
620 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
621 goto failed;
622 }
623
624 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
625 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
626 goto failed;
627 }
628
Johan Hedberg72a734e2010-12-30 00:38:22 +0200629 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200630 if (!cmd) {
631 err = -ENOMEM;
632 goto failed;
633 }
634
635 if (cp->val)
636 scan = SCAN_PAGE;
637 else
638 scan = 0;
639
640 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
641 if (err < 0)
642 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200643
644failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800645 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200646 hci_dev_put(hdev);
647
648 return err;
649}
650
651static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
652 struct sock *skip_sk)
653{
654 struct sk_buff *skb;
655 struct mgmt_hdr *hdr;
656
Brian Gixa68668b2011-08-11 15:49:36 -0700657 BT_DBG("hci%d %d", index, event);
658
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200659 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
660 if (!skb)
661 return -ENOMEM;
662
663 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
664
665 hdr = (void *) skb_put(skb, sizeof(*hdr));
666 hdr->opcode = cpu_to_le16(event);
667 hdr->index = cpu_to_le16(index);
668 hdr->len = cpu_to_le16(data_len);
669
670 if (data)
671 memcpy(skb_put(skb, data_len), data, data_len);
672
673 hci_send_to_sock(NULL, skb, skip_sk);
674 kfree_skb(skb);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200675
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200676 return 0;
677}
678
679static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
680{
681 struct mgmt_mode rp;
682
683 rp.val = val;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200684
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200685 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
686}
687
688static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
689 u16 len)
690{
691 struct mgmt_mode *cp, ev;
692 struct hci_dev *hdev;
693 int err;
694
695 cp = (void *) data;
696
697 BT_DBG("request for hci%u", index);
698
699 if (len != sizeof(*cp))
Johan Hedberg053f0212011-01-26 13:07:10 +0200700 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
701
702 hdev = hci_dev_get(index);
703 if (!hdev)
704 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
705
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800706 hci_dev_lock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200707
708 if (cp->val)
709 set_bit(HCI_PAIRABLE, &hdev->flags);
710 else
711 clear_bit(HCI_PAIRABLE, &hdev->flags);
712
713 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
714 if (err < 0)
715 goto failed;
716
717 ev.val = cp->val;
718
719 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
720
721failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800722 hci_dev_unlock_bh(hdev);
Johan Hedberg053f0212011-01-26 13:07:10 +0200723 hci_dev_put(hdev);
724
725 return err;
726}
727
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300728#define EIR_FLAGS 0x01 /* flags */
729#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
730#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
731#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
732#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
733#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
734#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
735#define EIR_NAME_SHORT 0x08 /* shortened local name */
736#define EIR_NAME_COMPLETE 0x09 /* complete local name */
737#define EIR_TX_POWER 0x0A /* transmit power level */
738#define EIR_DEVICE_ID 0x10 /* device ID */
739
740#define PNP_INFO_SVCLASS_ID 0x1200
741
742static u8 bluetooth_base_uuid[] = {
743 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
744 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745};
746
747static u16 get_uuid16(u8 *uuid128)
748{
749 u32 val;
750 int i;
751
752 for (i = 0; i < 12; i++) {
753 if (bluetooth_base_uuid[i] != uuid128[i])
754 return 0;
755 }
756
757 memcpy(&val, &uuid128[12], 4);
758
759 val = le32_to_cpu(val);
760 if (val > 0xffff)
761 return 0;
762
763 return (u16) val;
764}
765
766static void create_eir(struct hci_dev *hdev, u8 *data)
767{
768 u8 *ptr = data;
769 u16 eir_len = 0;
770 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
771 int i, truncated = 0;
772 struct list_head *p;
773 size_t name_len;
774
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530775 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300776
777 if (name_len > 0) {
778 /* EIR Data type */
779 if (name_len > 48) {
780 name_len = 48;
781 ptr[1] = EIR_NAME_SHORT;
782 } else
783 ptr[1] = EIR_NAME_COMPLETE;
784
785 /* EIR Data length */
786 ptr[0] = name_len + 1;
787
788 memcpy(ptr + 2, hdev->dev_name, name_len);
789
790 eir_len += (name_len + 2);
791 ptr += (name_len + 2);
792 }
793
794 memset(uuid16_list, 0, sizeof(uuid16_list));
795
796 /* Group all UUID16 types */
797 list_for_each(p, &hdev->uuids) {
798 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
799 u16 uuid16;
800
801 uuid16 = get_uuid16(uuid->uuid);
802 if (uuid16 == 0)
803 return;
804
805 if (uuid16 < 0x1100)
806 continue;
807
808 if (uuid16 == PNP_INFO_SVCLASS_ID)
809 continue;
810
811 /* Stop if not enough space to put next UUID */
812 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
813 truncated = 1;
814 break;
815 }
816
817 /* Check for duplicates */
818 for (i = 0; uuid16_list[i] != 0; i++)
819 if (uuid16_list[i] == uuid16)
820 break;
821
822 if (uuid16_list[i] == 0) {
823 uuid16_list[i] = uuid16;
824 eir_len += sizeof(u16);
825 }
826 }
827
828 if (uuid16_list[0] != 0) {
829 u8 *length = ptr;
830
831 /* EIR Data type */
832 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
833
834 ptr += 2;
835 eir_len += 2;
836
837 for (i = 0; uuid16_list[i] != 0; i++) {
838 *ptr++ = (uuid16_list[i] & 0x00ff);
839 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
840 }
841
842 /* EIR Data length */
843 *length = (i * sizeof(u16)) + 1;
844 }
845}
846
847static int update_eir(struct hci_dev *hdev)
848{
849 struct hci_cp_write_eir cp;
850
851 if (!(hdev->features[6] & LMP_EXT_INQ))
852 return 0;
853
854 if (hdev->ssp_mode == 0)
855 return 0;
856
857 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
858 return 0;
859
860 memset(&cp, 0, sizeof(cp));
861
862 create_eir(hdev, cp.data);
863
864 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
865 return 0;
866
867 memcpy(hdev->eir, cp.data, sizeof(cp.data));
868
869 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
870}
871
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200874 struct mgmt_cp_add_uuid *cp;
875 struct hci_dev *hdev;
876 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200877 int err;
878
879 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200880
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200882
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200883 if (len != sizeof(*cp))
884 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
885
886 hdev = hci_dev_get(index);
887 if (!hdev)
888 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
889
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800890 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200891
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
893 if (!uuid) {
894 err = -ENOMEM;
895 goto failed;
896 }
897
898 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200900
901 list_add(&uuid->list, &hdev->uuids);
902
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530903 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530905 err = update_class(hdev);
906 if (err < 0)
907 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300908
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530909 err = update_eir(hdev);
910 if (err < 0)
911 goto failed;
912 } else
913 err = 0;
Johan Hedberg90e70452012-02-23 23:09:40 +0200914
Szymon Janc4e51eae2011-02-25 19:05:48 +0100915 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200916
917failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800918 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200919 hci_dev_put(hdev);
920
921 return err;
922}
923
Szymon Janc4e51eae2011-02-25 19:05:48 +0100924static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg24b78d02012-02-23 23:24:30 +0200925{
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200926 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100927 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928 struct hci_dev *hdev;
929 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 +0200930 int err, found;
931
932 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200933
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200935
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200936 if (len != sizeof(*cp))
937 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
938
939 hdev = hci_dev_get(index);
940 if (!hdev)
941 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
942
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800943 hci_dev_lock_bh(hdev);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200944
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200945 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
946 err = hci_uuids_clear(hdev);
947 goto unlock;
948 }
949
950 found = 0;
951
952 list_for_each_safe(p, n, &hdev->uuids) {
953 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
954
955 if (memcmp(match->uuid, cp->uuid, 16) != 0)
956 continue;
957
958 list_del(&match->list);
959 found++;
960 }
961
962 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100963 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200964 goto unlock;
965 }
966
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530967 if (test_bit(HCI_UP, &hdev->flags)) {
968 err = update_class(hdev);
969 if (err < 0)
970 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200971
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530972 err = update_eir(hdev);
973 if (err < 0)
974 goto unlock;
975 } else
976 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300977
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200979
980unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800981 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200982 hci_dev_put(hdev);
983
984 return err;
985}
986
Szymon Janc4e51eae2011-02-25 19:05:48 +0100987static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
988 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989{
990 struct hci_dev *hdev;
991 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200992 int err;
993
994 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200995
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 if (len != sizeof(*cp))
999 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001000
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001001 hdev = hci_dev_get(index);
1002 if (!hdev)
1003 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
1004
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001005 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006
Brian Gix8a7f1642011-10-17 17:39:46 -07001007 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1008 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001009 hdev->minor_class = cp->minor;
1010
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301011 if (test_bit(HCI_UP, &hdev->flags)) {
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301012 err = update_class(hdev);
Srinivas Krovvidi58562d82012-06-25 16:46:56 +05301013 if (err == 0)
1014 err = cmd_complete(sk, index,
1015 MGMT_OP_SET_DEV_CLASS, hdev->dev_class, sizeof(u8)*3);
1016 } else
Szymon Janc4e51eae2011-02-25 19:05:48 +01001017 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001018
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001019 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001020 hci_dev_put(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001021
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001022 return err;
1023}
1024
Johan Hedberg03811012010-12-08 00:21:06 +02001025static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1026 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001027{
Johan Hedberg03811012010-12-08 00:21:06 +02001028 struct hci_dev *hdev;
1029 struct mgmt_cp_set_service_cache *cp;
1030 int err;
1031
1032 cp = (void *) data;
1033
1034 if (len != sizeof(*cp))
1035 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
1036
1037 hdev = hci_dev_get(index);
1038 if (!hdev)
1039 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
1040
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001041 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001042
1043 BT_DBG("hci%u enable %d", index, cp->enable);
1044
1045 if (cp->enable) {
1046 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1047 err = 0;
1048 } else {
1049 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301050 if (test_bit(HCI_UP, &hdev->flags)) {
1051 err = update_class(hdev);
1052 if (err == 0)
1053 err = update_eir(hdev);
1054 } else
1055 err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02001056 }
1057
1058 if (err == 0)
1059 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1060 0);
1061
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001062 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001063 hci_dev_put(hdev);
1064
1065 return err;
1066}
1067
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001068static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
1069{
1070 struct hci_dev *hdev;
1071 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001072 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001073 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001074
1075 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001076
1077 if (len < sizeof(*cp))
1078 return -EINVAL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001079
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080 key_count = get_unaligned_le16(&cp->key_count);
1081
1082 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001083 if (expected_len > len) {
1084 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1085 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086 return -EINVAL;
1087 }
1088
Szymon Janc4e51eae2011-02-25 19:05:48 +01001089 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001090 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001091 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001092
Szymon Janc4e51eae2011-02-25 19:05:48 +01001093 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001094 key_count);
1095
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001096 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001097
1098 hci_link_keys_clear(hdev);
1099
1100 set_bit(HCI_LINK_KEYS, &hdev->flags);
1101
1102 if (cp->debug_keys)
1103 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1104 else
1105 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1106
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001107 len -= sizeof(*cp);
1108 i = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001109
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001110 while (i < len) {
1111 struct mgmt_key_info *key = (void *) cp->keys + i;
1112
Brian Gixa68668b2011-08-11 15:49:36 -07001113 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001114
Brian Gixcf956772011-10-20 15:18:51 -07001115 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001116 struct key_master_id *id = (void *) key->data;
1117
1118 if (key->dlen != sizeof(struct key_master_id))
1119 continue;
1120
Brian Gixcf956772011-10-20 15:18:51 -07001121 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1122 key->pin_len, key->auth, id->ediv,
1123 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001124
1125 continue;
1126 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127
Brian Gixcf956772011-10-20 15:18:51 -07001128 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001129 key->pin_len);
1130 }
1131
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001132 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001133
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001134 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001135 hci_dev_put(hdev);
1136
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001137 return err;
1138}
1139
Johan Hedberg03811012010-12-08 00:21:06 +02001140static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001141{
Johan Hedberg03811012010-12-08 00:21:06 +02001142 struct hci_dev *hdev;
1143 struct mgmt_cp_remove_key *cp;
1144 struct hci_conn *conn;
1145 int err;
1146
1147 cp = (void *) data;
1148
1149 if (len != sizeof(*cp))
1150 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1151
1152 hdev = hci_dev_get(index);
1153 if (!hdev)
1154 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
1155
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001156 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001157
1158 err = hci_remove_link_key(hdev, &cp->bdaddr);
1159 if (err < 0) {
1160 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
1161 goto unlock;
1162 }
1163
1164 err = 0;
1165
1166 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1167 goto unlock;
1168
1169 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1170 if (conn) {
1171 struct hci_cp_disconnect dc;
1172
1173 put_unaligned_le16(conn->handle, &dc.handle);
1174 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02001176 }
1177
1178unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001179 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001180 hci_dev_put(hdev);
1181
1182 return err;
1183}
1184
Johan Hedberg8962ee72011-01-20 12:40:27 +02001185static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
1186{
1187 struct hci_dev *hdev;
1188 struct mgmt_cp_disconnect *cp;
1189 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001190 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001192 int err;
1193
1194 BT_DBG("");
1195
1196 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001198 if (len != sizeof(*cp))
1199 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1200
Szymon Janc4e51eae2011-02-25 19:05:48 +01001201 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001202 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001203 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001205 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001206
1207 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001208 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001209 goto failed;
1210 }
1211
Szymon Janc4e51eae2011-02-25 19:05:48 +01001212 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1213 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001214 goto failed;
1215 }
1216
1217 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1218 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001219 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1220 if (!conn) {
1221 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1222 ENOTCONN);
1223 goto failed;
1224 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001225 }
1226
Szymon Janc4e51eae2011-02-25 19:05:48 +01001227 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001228 if (!cmd) {
1229 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001230 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001231 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001232
1233 put_unaligned_le16(conn->handle, &dc.handle);
1234 dc.reason = 0x13; /* Remote User Terminated Connection */
1235
1236 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1237 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001238 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001239
1240failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001241 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001242 hci_dev_put(hdev);
1243
1244 return err;
1245}
1246
Szymon Janc8ce62842011-03-01 16:55:32 +01001247static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 struct mgmt_rp_get_connections *rp;
1250 struct hci_dev *hdev;
1251 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001252 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001253 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001254 int i, err;
1255
1256 BT_DBG("");
1257
Szymon Janc4e51eae2011-02-25 19:05:48 +01001258 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001260 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001262 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001263
1264 count = 0;
1265 list_for_each(p, &hdev->conn_hash.list) {
1266 count++;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001267 }
1268
Johan Hedberga38528f2011-01-22 06:46:43 +02001269 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1270 rp = kmalloc(rp_len, GFP_ATOMIC);
1271 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001272 err = -ENOMEM;
1273 goto unlock;
1274 }
1275
Johan Hedberg2784eb42011-01-21 13:56:35 +02001276 put_unaligned_le16(count, &rp->conn_count);
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 read_lock(&hci_dev_list_lock);
1279
Johan Hedberg2784eb42011-01-21 13:56:35 +02001280 i = 0;
1281 list_for_each(p, &hdev->conn_hash.list) {
1282 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1283
1284 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001285 }
1286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 read_unlock(&hci_dev_list_lock);
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001288
Szymon Janc4e51eae2011-02-25 19:05:48 +01001289 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001290
1291unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001292 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001293 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001294 hci_dev_put(hdev);
1295 return err;
1296}
1297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1299 u16 len)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001300{
Johan Hedberg980e1a52011-01-22 06:10:07 +02001301 struct hci_dev *hdev;
1302 struct mgmt_cp_pin_code_reply *cp;
1303 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001304 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001305 int err;
1306
1307 BT_DBG("");
1308
1309 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001310
Johan Hedberg980e1a52011-01-22 06:10:07 +02001311 if (len != sizeof(*cp))
1312 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1313
1314 hdev = hci_dev_get(index);
1315 if (!hdev)
1316 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
1317
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001318 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319
1320 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001322 goto failed;
1323 }
1324
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001326 if (!cmd) {
1327 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001329 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001330
1331 bacpy(&reply.bdaddr, &cp->bdaddr);
1332 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334
1335 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1336 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001337 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338
1339failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001340 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341 hci_dev_put(hdev);
1342
1343 return err;
1344}
1345
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301346static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1347 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001348{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301349 struct hci_dev *hdev;
1350 struct mgmt_cp_encrypt_link *cp;
1351 struct hci_cp_set_conn_encrypt enc;
1352 struct hci_conn *conn;
1353 int err = 0;
1354
1355 BT_DBG("");
1356
1357 cp = (void *) data;
1358
1359 if (len != sizeof(*cp))
1360 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1361
1362 hdev = hci_dev_get(index);
1363 if (!hdev)
1364 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1365
Brian Gix384ec672012-03-08 18:41:15 -08001366 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301367
1368 if (!test_bit(HCI_UP, &hdev->flags)) {
1369 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001370 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301371 }
1372
Brian Gix384ec672012-03-08 18:41:15 -08001373 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1374 if (!conn) {
1375 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1376 goto done;
1377 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301378
Brian Gix384ec672012-03-08 18:41:15 -08001379 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1380 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1381 goto done;
1382 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301383
1384 if (conn->link_mode & HCI_LM_AUTH) {
1385 enc.handle = cpu_to_le16(conn->handle);
1386 enc.encrypt = cp->enable;
1387 err = hci_send_cmd(hdev,
1388 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1389 } else {
1390 conn->auth_initiator = 1;
1391 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1392 struct hci_cp_auth_requested cp;
1393 cp.handle = cpu_to_le16(conn->handle);
1394 err = hci_send_cmd(conn->hdev,
1395 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1396 }
1397 }
1398
Brian Gix384ec672012-03-08 18:41:15 -08001399done:
1400 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301401 hci_dev_put(hdev);
1402
1403 return err;
1404}
1405
1406
Johan Hedberg980e1a52011-01-22 06:10:07 +02001407static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1408 u16 len)
1409{
1410 struct hci_dev *hdev;
1411 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001413 int err;
1414
1415 BT_DBG("");
1416
1417 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001418
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419 if (len != sizeof(*cp))
1420 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1421 EINVAL);
1422
1423 hdev = hci_dev_get(index);
1424 if (!hdev)
1425 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1426 ENODEV);
1427
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001428 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001429
1430 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1432 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001433 goto failed;
1434 }
1435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1437 data, len);
1438 if (!cmd) {
1439 err = -ENOMEM;
1440 goto failed;
1441 }
1442
1443 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1444 &cp->bdaddr);
1445 if (err < 0)
1446 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001447
1448failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001449 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001450 hci_dev_put(hdev);
1451
1452 return err;
1453}
1454
Sunny Kapdi93bef892012-07-30 14:52:56 -07001455static int le_add_dev_white_list(struct sock *sk, u16 index,
1456 unsigned char *data, u16 len)
1457{
1458 struct hci_dev *hdev;
1459 struct mgmt_cp_le_add_dev_white_list *cp;
1460 int err = 0;
1461
1462 BT_DBG("");
1463
1464 cp = (void *) data;
1465
1466 if (len != sizeof(*cp))
1467 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1468 EINVAL);
1469
1470 hdev = hci_dev_get(index);
1471 if (!hdev)
1472 return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1473 ENODEV);
1474
1475 hci_dev_lock_bh(hdev);
1476
1477 if (!test_bit(HCI_UP, &hdev->flags)) {
1478 err = cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
1479 ENETDOWN);
1480 goto failed;
1481 }
1482
1483 hci_le_add_dev_white_list(hdev, &cp->bdaddr);
1484
1485failed:
1486 hci_dev_unlock_bh(hdev);
1487 hci_dev_put(hdev);
1488
1489 return err;
1490}
1491
1492static int le_remove_dev_white_list(struct sock *sk, u16 index,
1493 unsigned char *data, u16 len)
1494{
1495 struct hci_dev *hdev;
1496 struct mgmt_cp_le_remove_dev_white_list *cp;
1497 int err = 0;
1498
1499 BT_DBG("");
1500
1501 cp = (void *) data;
1502
1503 if (len != sizeof(*cp))
1504 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1505 EINVAL);
1506
1507 hdev = hci_dev_get(index);
1508 if (!hdev)
1509 return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1510 ENODEV);
1511
1512 hci_dev_lock_bh(hdev);
1513
1514 if (!test_bit(HCI_UP, &hdev->flags)) {
1515 err = cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
1516 ENETDOWN);
1517 goto failed;
1518 }
1519
1520 hci_le_remove_dev_white_list(hdev, &cp->bdaddr);
1521
1522failed:
1523 hci_dev_unlock_bh(hdev);
1524 hci_dev_put(hdev);
1525
1526 return err;
1527}
1528
1529static int le_create_conn_white_list(struct sock *sk, u16 index)
1530{
1531 struct hci_dev *hdev;
1532 struct hci_conn *conn;
1533 u8 sec_level, auth_type;
1534 struct pending_cmd *cmd;
1535 bdaddr_t bdaddr;
1536 int err = 0;
1537
1538 BT_DBG("");
1539
1540 hdev = hci_dev_get(index);
1541 if (!hdev)
1542 return cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1543 ENODEV);
1544
1545 hci_dev_lock_bh(hdev);
1546
1547 if (!test_bit(HCI_UP, &hdev->flags)) {
1548 err = cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
1549 ENETDOWN);
1550 goto failed;
1551 }
1552
1553 cmd = mgmt_pending_add(sk, MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index,
1554 NULL, 0);
1555 if (!cmd) {
1556 err = -ENOMEM;
1557 goto failed;
1558 }
1559
1560 sec_level = BT_SECURITY_MEDIUM;
1561 auth_type = HCI_AT_GENERAL_BONDING;
1562 memset(&bdaddr, 0, sizeof(bdaddr));
1563 conn = hci_le_connect(hdev, 0, BDADDR_ANY, sec_level, auth_type, NULL);
1564 if (IS_ERR(conn)) {
1565 err = PTR_ERR(conn);
1566 mgmt_pending_remove(cmd);
1567 }
1568
1569failed:
1570 hci_dev_unlock_bh(hdev);
1571 hci_dev_put(hdev);
1572
1573 return err;
1574}
1575
1576static int le_cancel_create_conn_white_list(struct sock *sk, u16 index)
1577{
1578 struct hci_dev *hdev;
1579 int err = 0;
1580
1581 BT_DBG("");
1582
1583 hdev = hci_dev_get(index);
1584 if (!hdev)
1585 return cmd_status(sk, index,
1586 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENODEV);
1587
1588 hci_dev_lock_bh(hdev);
1589
1590 if (!test_bit(HCI_UP, &hdev->flags)) {
1591 err = cmd_status(sk, index,
1592 MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENETDOWN);
1593 goto failed;
1594 }
1595
1596 hci_le_cancel_create_connect(hdev, BDADDR_ANY);
1597
1598failed:
1599 hci_dev_unlock_bh(hdev);
1600 hci_dev_put(hdev);
1601
1602 return err;
1603}
1604
1605static int le_clear_white_list(struct sock *sk, u16 index)
1606{
1607 struct hci_dev *hdev;
1608 int err;
1609
1610 BT_DBG("");
1611
1612 hdev = hci_dev_get(index);
1613 if (!hdev)
1614 return cmd_status(sk, index,
1615 MGMT_OP_LE_CLEAR_WHITE_LIST, ENODEV);
1616
1617 hci_dev_lock_bh(hdev);
1618
1619 if (!test_bit(HCI_UP, &hdev->flags)) {
1620 err = cmd_status(sk, index,
1621 MGMT_OP_LE_CLEAR_WHITE_LIST, ENETDOWN);
1622 goto failed;
1623 }
1624
1625 err = hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
1626
1627failed:
1628 hci_dev_unlock_bh(hdev);
1629 hci_dev_put(hdev);
1630
1631 return err;
1632}
1633
Szymon Janc4e51eae2011-02-25 19:05:48 +01001634static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1635 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001636{
1637 struct hci_dev *hdev;
1638 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001639
1640 BT_DBG("");
1641
1642 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001643
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001644 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001645 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001646
Szymon Janc4e51eae2011-02-25 19:05:48 +01001647 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001648 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001649 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001650
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001651 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001652
1653 hdev->io_capability = cp->io_capability;
1654
1655 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001656 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001657
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001658 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001659 hci_dev_put(hdev);
1660
Szymon Janc4e51eae2011-02-25 19:05:48 +01001661 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001662}
1663
Johan Hedberge9a416b2011-02-19 12:05:56 -03001664static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1665{
1666 struct hci_dev *hdev = conn->hdev;
1667 struct list_head *p;
1668
1669 list_for_each(p, &cmd_list) {
1670 struct pending_cmd *cmd;
1671
1672 cmd = list_entry(p, struct pending_cmd, list);
1673
1674 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1675 continue;
1676
1677 if (cmd->index != hdev->id)
1678 continue;
1679
1680 if (cmd->user_data != conn)
1681 continue;
1682
1683 return cmd;
1684 }
1685
1686 return NULL;
1687}
1688
1689static void pairing_complete(struct pending_cmd *cmd, u8 status)
1690{
1691 struct mgmt_rp_pair_device rp;
1692 struct hci_conn *conn = cmd->user_data;
1693
Brian Gixa68668b2011-08-11 15:49:36 -07001694 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001695
Johan Hedberge9a416b2011-02-19 12:05:56 -03001696 bacpy(&rp.bdaddr, &conn->dst);
1697 rp.status = status;
1698
Szymon Janc4e51eae2011-02-25 19:05:48 +01001699 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001700
1701 /* So we don't get further callbacks for this connection */
1702 conn->connect_cfm_cb = NULL;
1703 conn->security_cfm_cb = NULL;
1704 conn->disconn_cfm_cb = NULL;
1705
Johan Hedberga664b5b2011-02-19 12:06:02 -03001706 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001707}
1708
1709static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1710{
1711 struct pending_cmd *cmd;
1712
Brian Gixa68668b2011-08-11 15:49:36 -07001713 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001714
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001715 cmd = find_pairing(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001716 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001717 BT_DBG("Unable to find a pending command");
Johan Hedberge9a416b2011-02-19 12:05:56 -03001718 return;
1719 }
1720
1721 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001722 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001723}
1724
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001725static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726{
Johan Hedberge9a416b2011-02-19 12:05:56 -03001727 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001728
1729 BT_DBG(" %u", status);
1730
1731 cmd = find_pairing(conn);
1732 if (!cmd) {
1733 BT_DBG("Unable to find a pending command");
1734 return;
1735 }
1736
1737 if (conn->type == LE_LINK)
1738 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1739 status ? 0 : 1);
1740 else
1741 pairing_complete(cmd, status);
1742}
1743
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001744static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001745{
1746 struct pending_cmd *cmd;
1747
1748 BT_DBG("conn: %p %u", conn, status);
1749
1750 cmd = find_pairing(conn);
1751 if (!cmd) {
1752 BT_DBG("Unable to find a pending command");
1753 return;
1754 }
Brian Gix114f3a62011-09-27 14:02:20 -07001755
1756 if (status)
1757 pairing_complete(cmd, status);
1758
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001759 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001760}
1761
1762static void discovery_terminated(struct pending_cmd *cmd, void *data)
1763{
Brian Gix6e349d02011-11-28 14:51:14 -08001764 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001765 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001766
1767 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001768 hdev = hci_dev_get(cmd->index);
1769 if (!hdev)
1770 goto not_found;
1771
Brian Gix568dde92012-01-11 16:18:04 -08001772 del_timer(&hdev->disco_le_timer);
1773 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001774 hci_dev_put(hdev);
1775
1776not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001777 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1778
1779 list_del(&cmd->list);
1780
1781 mgmt_pending_free(cmd);
1782}
1783
Johan Hedberge9a416b2011-02-19 12:05:56 -03001784static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
1785{
1786 struct hci_dev *hdev;
1787 struct mgmt_cp_pair_device *cp;
1788 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001789 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001790 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001791 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001792 int err;
1793
1794 BT_DBG("");
1795
Brian Gix64bd5302011-09-08 11:35:48 -07001796 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001797
Brian Gix64bd5302011-09-08 11:35:48 -07001798 if (len != sizeof(*cp))
1799 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1800
Johan Hedberge9a416b2011-02-19 12:05:56 -03001801 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001802
Johan Hedberge9a416b2011-02-19 12:05:56 -03001803 if (!hdev)
1804 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
1805
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001806 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001807
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301808 io_cap = cp->io_cap;
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001809
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001810 sec_level = BT_SECURITY_MEDIUM;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301811 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812
Brian Gixfdd38922011-09-28 16:23:48 -07001813 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1814 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001815 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1816 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001817 } else {
1818 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1819 if (io_cap == 0x04)
1820 io_cap = 0x01;
1821 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1822 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301823 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001824 }
Johan Hedberg1425acb2011-11-11 00:07:35 +02001825
Ville Tervo30e76272011-02-22 16:10:53 -03001826 if (IS_ERR(conn)) {
1827 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828 goto unlock;
1829 }
1830
1831 if (conn->connect_cfm_cb) {
1832 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001833 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001834 goto unlock;
1835 }
1836
Szymon Janc4e51eae2011-02-25 19:05:48 +01001837 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001838 if (!cmd) {
1839 err = -ENOMEM;
1840 hci_conn_put(conn);
1841 goto unlock;
1842 }
1843
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001844 conn->connect_cfm_cb = pairing_connect_complete_cb;
1845 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001847 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001848 cmd->user_data = conn;
1849
1850 if (conn->state == BT_CONNECTED &&
1851 hci_conn_security(conn, sec_level, auth_type))
1852 pairing_complete(cmd, 0);
1853
1854 err = 0;
1855
1856unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001857 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858 hci_dev_put(hdev);
1859
1860 return err;
1861}
1862
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001864 u16 len, u16 opcode)
Johan Hedberg28424702012-02-02 04:02:29 +02001865{
Johan Hedberga5c29682011-02-19 12:05:57 -03001866 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001867 u16 mgmt_op = opcode, hci_op;
Johan Hedberg28424702012-02-02 04:02:29 +02001868 struct pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03001869 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001870 struct hci_conn *le_conn;
Johan Hedberg28424702012-02-02 04:02:29 +02001871 int err;
1872
Brian Gixa68668b2011-08-11 15:49:36 -07001873 BT_DBG("%d", mgmt_op);
Johan Hedberg28424702012-02-02 04:02:29 +02001874
Brian Gixa68668b2011-08-11 15:49:36 -07001875 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001876 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Johan Hedberg272d90d2012-02-09 15:26:12 +02001877 else
Brian Gixa68668b2011-08-11 15:49:36 -07001878 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Brian Gix47c15e22011-11-16 13:53:14 -08001879
Brian Gixa68668b2011-08-11 15:49:36 -07001880 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001881 return cmd_status(sk, index, mgmt_op, EINVAL);
1882
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001884 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001886
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001887 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001888
Johan Hedberga5c29682011-02-19 12:05:57 -03001889 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberg272d90d2012-02-09 15:26:12 +02001891 goto done;
1892 }
1893
Brian Gixa68668b2011-08-11 15:49:36 -07001894 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1895 if (le_conn) {
1896 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
Brian Gix47c15e22011-11-16 13:53:14 -08001897 goto done;
1898 }
Brian Gixa68668b2011-08-11 15:49:36 -07001899 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1900 "Reject" : "Accept");
Brian Gix47c15e22011-11-16 13:53:14 -08001901
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001903 if (!cmd) {
1904 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001905 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001906 }
1907
Brian Gixa68668b2011-08-11 15:49:36 -07001908 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001909 if (err < 0)
1910 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001911
Brian Gix0df4c182011-11-16 13:53:13 -08001912done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001913 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001914 hci_dev_put(hdev);
1915
Johan Hedberga5c29682011-02-19 12:05:57 -03001916 return err;
1917}
1918
Brian Gixa68668b2011-08-11 15:49:36 -07001919static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1920 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08001921{
Brian Gixa68668b2011-08-11 15:49:36 -07001922 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1923 struct hci_cp_remote_name_req hci_cp;
1924 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001925 struct pending_cmd *cmd;
1926 int err;
1927
1928 BT_DBG("");
1929
Brian Gixa68668b2011-08-11 15:49:36 -07001930 if (len != sizeof(*mgmt_cp))
1931 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001932
Brian Gixa68668b2011-08-11 15:49:36 -07001933 hdev = hci_dev_get(index);
1934 if (!hdev)
1935 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001936
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001937 hci_dev_lock_bh(hdev);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02001938
Brian Gixa68668b2011-08-11 15:49:36 -07001939 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001940 if (!cmd) {
1941 err = -ENOMEM;
1942 goto failed;
1943 }
1944
Brian Gixa68668b2011-08-11 15:49:36 -07001945 memset(&hci_cp, 0, sizeof(hci_cp));
1946 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1947 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1948 &hci_cp);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001949 if (err < 0)
1950 mgmt_pending_remove(cmd);
1951
1952failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001953 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001954 hci_dev_put(hdev);
1955
Johan Hedbergb312b1612011-03-16 14:29:37 +02001956 return err;
1957}
1958
Brian Gix7f7e16c2011-11-01 16:27:25 -07001959static int set_connection_params(struct sock *sk, u16 index,
1960 unsigned char *data, u16 len)
Szymon Jancc35938b2011-03-22 13:12:21 +01001961{
Brian Gix7f7e16c2011-11-01 16:27:25 -07001962 struct mgmt_cp_set_connection_params *cp = (void *) data;
1963 struct hci_dev *hdev;
1964 struct hci_conn *conn;
1965 int err;
1966
1967 BT_DBG("");
1968
1969 if (len != sizeof(*cp))
1970 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1971 EINVAL);
1972
1973 hdev = hci_dev_get(index);
1974 if (!hdev)
1975 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1976 ENODEV);
1977
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001978 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001979
1980 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1981 if (!conn) {
1982 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1983 ENOTCONN);
1984 goto failed;
1985 }
1986
1987 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1988 le16_to_cpu(cp->interval_max),
1989 le16_to_cpu(cp->slave_latency),
1990 le16_to_cpu(cp->timeout_multiplier));
1991
1992 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1993
1994failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001995 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001996 hci_dev_put(hdev);
1997
1998 return err;
1999}
2000
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002001static int set_rssi_reporter(struct sock *sk, u16 index,
2002 unsigned char *data, u16 len)
2003{
2004 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
2005 struct hci_dev *hdev;
2006 struct hci_conn *conn;
2007 int err = 0;
2008
2009 if (len != sizeof(*cp))
2010 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2011 EINVAL);
2012
2013 hdev = hci_dev_get(index);
2014 if (!hdev)
2015 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2016 ENODEV);
2017
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002018 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002019
2020 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2021
2022 if (!conn) {
2023 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
2024 ENOTCONN);
2025 goto failed;
2026 }
2027
2028 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
2029 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
2030 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
2031
2032failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002033 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002034 hci_dev_put(hdev);
2035
2036 return err;
2037}
2038
2039static int unset_rssi_reporter(struct sock *sk, u16 index,
2040 unsigned char *data, u16 len)
2041{
2042 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
2043 struct hci_dev *hdev;
2044 struct hci_conn *conn;
2045 int err = 0;
2046
2047 if (len != sizeof(*cp))
2048 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2049 EINVAL);
2050
2051 hdev = hci_dev_get(index);
2052
2053 if (!hdev)
2054 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2055 ENODEV);
2056
Archana Ramachandranf32d9822012-04-09 17:52:01 -07002057 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002058
2059 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
2060
2061 if (!conn) {
2062 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
2063 ENOTCONN);
2064 goto failed;
2065 }
2066
2067 hci_conn_unset_rssi_reporter(conn);
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
Johan Hedberg03811012010-12-08 00:21:06 +02002076static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
2077 u16 len)
2078{
2079 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
2080 struct hci_cp_write_local_name hci_cp;
2081 struct hci_dev *hdev;
Szymon Jancc35938b2011-03-22 13:12:21 +01002082 struct pending_cmd *cmd;
2083 int err;
2084
Johan Hedberg03811012010-12-08 00:21:06 +02002085 BT_DBG("");
Szymon Jancc35938b2011-03-22 13:12:21 +01002086
Johan Hedberg03811012010-12-08 00:21:06 +02002087 if (len != sizeof(*mgmt_cp))
2088 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
Szymon Jancc35938b2011-03-22 13:12:21 +01002089
Johan Hedberg03811012010-12-08 00:21:06 +02002090 hdev = hci_dev_get(index);
2091 if (!hdev)
2092 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
2093
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002094 hci_dev_lock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002095
2096 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
2097 if (!cmd) {
2098 err = -ENOMEM;
2099 goto failed;
2100 }
2101
2102 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2103 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2104 &hci_cp);
2105 if (err < 0)
2106 mgmt_pending_remove(cmd);
2107
2108failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002109 hci_dev_unlock_bh(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002110 hci_dev_put(hdev);
2111
2112 return err;
2113}
2114
Brian Gixa68668b2011-08-11 15:49:36 -07002115static void discovery_rsp(struct pending_cmd *cmd, void *data)
2116{
2117 struct mgmt_mode ev;
2118
2119 BT_DBG("");
2120 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
2121 ev.val = 1;
2122 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
2123 } else {
2124 ev.val = 0;
2125 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
2126 NULL, 0);
2127 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08002128 struct hci_dev *hdev = hci_dev_get(cmd->index);
2129 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08002130 del_timer(&hdev->disco_le_timer);
2131 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08002132 hci_dev_put(hdev);
2133 }
Brian Gixa68668b2011-08-11 15:49:36 -07002134 }
2135 }
2136
2137 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
2138
2139 list_del(&cmd->list);
2140
2141 mgmt_pending_free(cmd);
2142}
2143
2144void mgmt_inquiry_started(u16 index)
2145{
2146 BT_DBG("");
2147 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
2148 discovery_rsp, NULL);
2149}
2150
2151void mgmt_inquiry_complete_evt(u16 index, u8 status)
2152{
2153 struct hci_dev *hdev;
2154 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08002155 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002156 int err = -1;
2157
2158 BT_DBG("");
2159
2160 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07002161
Brian Gixa68668b2011-08-11 15:49:36 -07002162 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07002163
2164 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2165 discovery_terminated, NULL);
2166
2167 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002168
Brian Gix64bd5302011-09-08 11:35:48 -07002169 if (hdev)
2170 goto done;
2171 else
2172 return;
2173 }
Brian Gixa68668b2011-08-11 15:49:36 -07002174
Brian Gix568dde92012-01-11 16:18:04 -08002175 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002176 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2177 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002178 if (err >= 0) {
2179 mod_timer(&hdev->disco_le_timer, jiffies +
2180 msecs_to_jiffies(hdev->disco_int_phase * 1000));
2181 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07002182 } else
Brian Gix568dde92012-01-11 16:18:04 -08002183 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002184 }
2185
Brian Gix568dde92012-01-11 16:18:04 -08002186 if (hdev->disco_state == SCAN_IDLE)
2187 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2188
Brian Gixa68668b2011-08-11 15:49:36 -07002189 if (err < 0)
2190 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2191 discovery_terminated, NULL);
2192
Brian Gix64bd5302011-09-08 11:35:48 -07002193done:
Brian Gixa68668b2011-08-11 15:49:36 -07002194 hci_dev_put(hdev);
2195}
2196
Brian Gix568dde92012-01-11 16:18:04 -08002197void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002198{
Brian Gix568dde92012-01-11 16:18:04 -08002199 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002200 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002201 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002202
Brian Gix568dde92012-01-11 16:18:04 -08002203 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002204
Brian Gix568dde92012-01-11 16:18:04 -08002205 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002206
Brian Gix568dde92012-01-11 16:18:04 -08002207 if (!hdev)
2208 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002209
Brian Gix568dde92012-01-11 16:18:04 -08002210 hci_dev_lock_bh(hdev);
2211 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002212
Brian Gix568dde92012-01-11 16:18:04 -08002213 if (hdev->disco_state != SCAN_IDLE) {
2214 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002215
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302216 if (test_bit(HCI_UP, &hdev->flags)) {
2217 if (hdev->disco_state == SCAN_LE)
2218 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002219 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302220 else
2221 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2222 NULL);
2223 }
Brian Gix568dde92012-01-11 16:18:04 -08002224 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002225 }
Brian Gix568dde92012-01-11 16:18:04 -08002226
2227 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2228
2229 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2230 if (cmd)
2231 mgmt_pending_remove(cmd);
2232
2233 hci_dev_unlock_bh(hdev);
2234 hci_dev_put(hdev);
2235}
2236
2237void mgmt_disco_le_timeout(unsigned long data)
2238{
2239 struct hci_dev *hdev = (void *)data;
2240 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2241
2242 BT_DBG("hci%d", hdev->id);
2243
2244 hdev = hci_dev_get(hdev->id);
2245
2246 if (!hdev)
2247 return;
2248
2249 hci_dev_lock_bh(hdev);
2250
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302251 if (test_bit(HCI_UP, &hdev->flags)) {
2252 if (hdev->disco_state == SCAN_LE)
2253 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2254 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002255
2256 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302257 if (hdev->disco_state != SCAN_IDLE) {
2258 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2259 hdev->disco_int_phase *= 2;
2260 hdev->disco_int_count = 0;
2261 cp.num_rsp = (u8) hdev->disco_int_phase;
2262 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2263 hdev->disco_state = SCAN_BR;
2264 }
Brian Gix568dde92012-01-11 16:18:04 -08002265 }
2266
2267 hci_dev_unlock_bh(hdev);
2268 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002269}
2270
2271static int start_discovery(struct sock *sk, u16 index)
2272{
2273 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2274 struct hci_dev *hdev;
2275 struct pending_cmd *cmd;
2276 int err;
2277
2278 BT_DBG("");
2279
2280 hdev = hci_dev_get(index);
2281 if (!hdev)
2282 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2283
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002284 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002285
Brian Gix568dde92012-01-11 16:18:04 -08002286 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2287 err = -EBUSY;
2288 goto failed;
2289 }
2290
Brian Gixa68668b2011-08-11 15:49:36 -07002291 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2292 if (!cmd) {
2293 err = -ENOMEM;
2294 goto failed;
2295 }
2296
2297 /* If LE Capable, we will alternate between BR/EDR and LE */
2298 if (lmp_le_capable(hdev)) {
2299 struct hci_cp_le_set_scan_parameters le_cp;
2300
2301 /* Shorten BR scan params */
2302 cp.num_rsp = 1;
2303 cp.length /= 2;
2304
2305 /* Setup LE scan params */
2306 memset(&le_cp, 0, sizeof(le_cp));
2307 le_cp.type = 0x01; /* Active scanning */
2308 /* The recommended value for scan interval and window is
2309 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2310 le_cp.interval = cpu_to_le16(0x0012);
2311 le_cp.window = cpu_to_le16(0x0012);
2312 le_cp.own_bdaddr_type = 0; /* Public address */
2313 le_cp.filter = 0; /* Accept all adv packets */
2314
2315 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2316 sizeof(le_cp), &le_cp);
2317 }
2318
2319 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2320
Bhasker Neti09760742012-05-25 12:30:39 +05302321 if (err < 0) {
Brian Gixa68668b2011-08-11 15:49:36 -07002322 mgmt_pending_remove(cmd);
Bhasker Neti09760742012-05-25 12:30:39 +05302323 hdev->disco_state = SCAN_IDLE;
2324 } else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002325 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2326 if (!cmd)
2327 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2328 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002329 hdev->disco_int_phase = 1;
2330 hdev->disco_int_count = 0;
2331 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002332 del_timer(&hdev->disco_le_timer);
2333 del_timer(&hdev->disco_timer);
2334 mod_timer(&hdev->disco_timer,
2335 jiffies + msecs_to_jiffies(20000));
Bhasker Neti09760742012-05-25 12:30:39 +05302336 } else
2337 hdev->disco_state = SCAN_BR;
Brian Gixa68668b2011-08-11 15:49:36 -07002338
2339failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002340 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002341 hci_dev_put(hdev);
2342
Brian Gix568dde92012-01-11 16:18:04 -08002343 if (err < 0)
2344 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2345
Brian Gixa68668b2011-08-11 15:49:36 -07002346 return err;
2347}
2348
2349static int stop_discovery(struct sock *sk, u16 index)
2350{
2351 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2352 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002353 struct hci_dev *hdev;
2354 struct pending_cmd *cmd = NULL;
2355 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002356 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002357
2358 BT_DBG("");
2359
2360 hdev = hci_dev_get(index);
2361 if (!hdev)
2362 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2363
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002364 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002365
Brian Gix568dde92012-01-11 16:18:04 -08002366 state = hdev->disco_state;
2367 hdev->disco_state = SCAN_IDLE;
2368 del_timer(&hdev->disco_le_timer);
2369 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002370
Brian Gix568dde92012-01-11 16:18:04 -08002371 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002372 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2373 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002374 if (err >= 0) {
2375 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2376 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002377
Brian Gix568dde92012-01-11 16:18:04 -08002378 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2379 NULL, 0);
2380 }
Bhasker Neti09760742012-05-25 12:30:39 +05302381 } else if (state == SCAN_BR)
Brian Gix568dde92012-01-11 16:18:04 -08002382 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002383
Brian Gix568dde92012-01-11 16:18:04 -08002384 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002385 if (err < 0 && cmd)
2386 mgmt_pending_remove(cmd);
2387
2388 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2389
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002390 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002391 hci_dev_put(hdev);
2392
2393 if (err < 0)
2394 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2395 else
2396 return err;
2397}
2398
Szymon Jancc35938b2011-03-22 13:12:21 +01002399static int read_local_oob_data(struct sock *sk, u16 index)
2400{
2401 struct hci_dev *hdev;
2402 struct pending_cmd *cmd;
2403 int err;
2404
2405 BT_DBG("hci%u", index);
2406
2407 hdev = hci_dev_get(index);
2408 if (!hdev)
2409 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2410 ENODEV);
2411
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002412 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002413
2414 if (!test_bit(HCI_UP, &hdev->flags)) {
2415 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2416 ENETDOWN);
2417 goto unlock;
2418 }
2419
2420 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2421 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2422 EOPNOTSUPP);
2423 goto unlock;
2424 }
2425
2426 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2427 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2428 goto unlock;
2429 }
2430
2431 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2432 if (!cmd) {
2433 err = -ENOMEM;
2434 goto unlock;
2435 }
2436
2437 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2438 if (err < 0)
2439 mgmt_pending_remove(cmd);
2440
2441unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002442 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002443 hci_dev_put(hdev);
2444
2445 return err;
2446}
2447
Szymon Janc2763eda2011-03-22 13:12:22 +01002448static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2449 u16 len)
2450{
2451 struct hci_dev *hdev;
2452 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2453 int err;
2454
2455 BT_DBG("hci%u ", index);
2456
2457 if (len != sizeof(*cp))
2458 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2459 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002460
Szymon Janc2763eda2011-03-22 13:12:22 +01002461 hdev = hci_dev_get(index);
2462 if (!hdev)
2463 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2464 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002465
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002466 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002467
2468 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2469 cp->randomizer);
2470 if (err < 0)
2471 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2472 else
2473 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2474 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002475
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002476 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002477 hci_dev_put(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002478
Szymon Janc2763eda2011-03-22 13:12:22 +01002479 return err;
2480}
2481
2482static int remove_remote_oob_data(struct sock *sk, u16 index,
2483 unsigned char *data, u16 len)
2484{
2485 struct hci_dev *hdev;
2486 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2487 int err;
2488
2489 BT_DBG("hci%u ", index);
2490
2491 if (len != sizeof(*cp))
2492 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2493 EINVAL);
Szymon Janc2763eda2011-03-22 13:12:22 +01002494
Szymon Janc2763eda2011-03-22 13:12:22 +01002495 hdev = hci_dev_get(index);
2496 if (!hdev)
2497 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2498 ENODEV);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002499
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002500 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002501
2502 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2503 if (err < 0)
2504 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2505 -err);
2506 else
2507 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2508 NULL, 0);
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002509
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002510 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002511 hci_dev_put(hdev);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002512
2513 return err;
2514}
2515
Johan Hedberg03811012010-12-08 00:21:06 +02002516int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2517{
2518 unsigned char *buf;
2519 struct mgmt_hdr *hdr;
2520 u16 opcode, index, len;
2521 int err;
2522
2523 BT_DBG("got %zu bytes", msglen);
2524
2525 if (msglen < sizeof(*hdr))
2526 return -EINVAL;
2527
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002528 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002529 if (!buf)
2530 return -ENOMEM;
2531
2532 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2533 err = -EFAULT;
2534 goto done;
2535 }
2536
2537 hdr = (struct mgmt_hdr *) buf;
2538 opcode = get_unaligned_le16(&hdr->opcode);
2539 index = get_unaligned_le16(&hdr->index);
2540 len = get_unaligned_le16(&hdr->len);
2541
2542 if (len != msglen - sizeof(*hdr)) {
2543 err = -EINVAL;
2544 goto done;
2545 }
2546
Brian Gixa68668b2011-08-11 15:49:36 -07002547 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002548 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002549 case MGMT_OP_READ_VERSION:
2550 err = read_version(sk);
2551 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002552 case MGMT_OP_READ_INDEX_LIST:
2553 err = read_index_list(sk);
2554 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002555 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002556 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002557 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002558 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002559 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002560 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002561 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002562 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002563 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002564 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2565 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2566 len);
2567 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002568 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002569 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002570 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002571 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002572 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002573 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002574 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002575 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002576 break;
2577 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002578 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002579 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002580 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002581 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002582 break;
2583 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002584 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002585 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002586 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002587 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002588 break;
2589 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002590 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002591 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002592 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002593 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002594 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002595 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002596 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002597 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002598 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002599 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002600 break;
2601 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002602 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002603 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002604 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002605 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002606 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002607 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002608 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002609 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002610 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002611 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002612 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002613 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2614 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002615 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002616 case MGMT_OP_SET_LOCAL_NAME:
2617 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2618 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002619 case MGMT_OP_START_DISCOVERY:
2620 err = start_discovery(sk, index);
2621 break;
2622 case MGMT_OP_STOP_DISCOVERY:
2623 err = stop_discovery(sk, index);
2624 break;
2625 case MGMT_OP_RESOLVE_NAME:
2626 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2627 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002628 case MGMT_OP_SET_CONNECTION_PARAMS:
2629 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2630 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002631 case MGMT_OP_SET_RSSI_REPORTER:
2632 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2633 break;
2634 case MGMT_OP_UNSET_RSSI_REPORTER:
2635 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2636 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002637 case MGMT_OP_READ_LOCAL_OOB_DATA:
2638 err = read_local_oob_data(sk, index);
2639 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002640 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2641 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2642 break;
2643 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2644 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2645 len);
2646 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302647 case MGMT_OP_ENCRYPT_LINK:
2648 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2649 break;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002650 case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
2651 err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
2652 len);
2653 break;
2654 case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
2655 err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
2656 len);
2657 break;
2658 case MGMT_OP_LE_CLEAR_WHITE_LIST:
2659 err = le_clear_white_list(sk, index);
2660 break;
2661 case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
2662 err = le_create_conn_white_list(sk, index);
2663 break;
2664 case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
2665 err = le_cancel_create_conn_white_list(sk, index);
2666 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002667 default:
2668 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002669 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002670 break;
2671 }
2672
Johan Hedberge41d8b42010-12-13 21:07:03 +02002673 if (err < 0)
2674 goto done;
2675
Johan Hedberg03811012010-12-08 00:21:06 +02002676 err = msglen;
2677
2678done:
2679 kfree(buf);
2680 return err;
2681}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002682
Johan Hedbergb24752f2011-11-03 14:40:33 +02002683static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2684{
2685 u8 *status = data;
2686
2687 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2688 mgmt_pending_remove(cmd);
2689}
2690
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002691int mgmt_index_added(u16 index)
2692{
Brian Gixa68668b2011-08-11 15:49:36 -07002693 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002694 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002695}
2696
2697int mgmt_index_removed(u16 index)
2698{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002699 u8 status = ENODEV;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002700
Brian Gixa68668b2011-08-11 15:49:36 -07002701 BT_DBG("%d", index);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002702
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002703 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2704
Szymon Janc4e51eae2011-02-25 19:05:48 +01002705 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002706}
2707
Johan Hedberg73f22f62010-12-29 16:00:25 +02002708struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002709 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002710 struct sock *sk;
2711};
2712
Johan Hedberg72a734e2010-12-30 00:38:22 +02002713static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002714{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002715 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002716 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002717
Johan Hedberg72a734e2010-12-30 00:38:22 +02002718 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002719 return;
2720
Johan Hedberg053f0212011-01-26 13:07:10 +02002721 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002722
2723 list_del(&cmd->list);
2724
2725 if (match->sk == NULL) {
2726 match->sk = cmd->sk;
2727 sock_hold(match->sk);
2728 }
2729
2730 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002731}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002732
2733int mgmt_powered(u16 index, u8 powered)
2734{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002735 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002736 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002737 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002738
Brian Gixa68668b2011-08-11 15:49:36 -07002739 BT_DBG("hci%u %d", index, powered);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002740
Johan Hedberg72a734e2010-12-30 00:38:22 +02002741 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002742
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002743 if (!powered) {
2744 u8 status = ENETDOWN;
2745 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002746 }
2747
Johan Hedberg72a734e2010-12-30 00:38:22 +02002748 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002749
Szymon Janc4e51eae2011-02-25 19:05:48 +01002750 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002751
2752 if (match.sk)
2753 sock_put(match.sk);
2754
2755 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002756}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002757
Johan Hedberg73f22f62010-12-29 16:00:25 +02002758int mgmt_discoverable(u16 index, u8 discoverable)
2759{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002760 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002761 struct cmd_lookup match = { discoverable, NULL };
2762 int ret;
2763
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002764 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002765
Johan Hedberg73f22f62010-12-29 16:00:25 +02002766 ev.val = discoverable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002767
Szymon Janc4e51eae2011-02-25 19:05:48 +01002768 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2769 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002770
Johan Hedberg73f22f62010-12-29 16:00:25 +02002771 if (match.sk)
2772 sock_put(match.sk);
2773
2774 return ret;
2775}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002776
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002777int mgmt_connectable(u16 index, u8 connectable)
2778{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002779 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002780 struct cmd_lookup match = { connectable, NULL };
2781 int ret;
2782
Johan Hedberg72a734e2010-12-30 00:38:22 +02002783 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002784
Johan Hedberg03811012010-12-08 00:21:06 +02002785 ev.val = connectable;
Johan Hedberged9b5f22012-02-21 20:47:06 +02002786
Szymon Janc4e51eae2011-02-25 19:05:48 +01002787 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002788
2789 if (match.sk)
2790 sock_put(match.sk);
2791
2792 return ret;
2793}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002794
Brian Gixa68668b2011-08-11 15:49:36 -07002795int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002796{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002797 struct mgmt_ev_new_key *ev;
2798 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002799
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002800 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2801 ev = kzalloc(total, GFP_ATOMIC);
2802 if (!ev)
2803 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002804
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002805 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002806 ev->key.addr_type = key->addr_type;
2807 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002808 memcpy(ev->key.val, key->val, 16);
2809 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002810 ev->key.auth = key->auth;
2811 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002812 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002813
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002814 memcpy(ev->key.data, key->data, key->dlen);
2815
2816 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2817
2818 kfree(ev);
2819
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002820 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002821}
2822
Brian Gix2e2f50d2011-09-13 12:36:04 -07002823int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002824{
Johan Hedbergf7520542011-01-20 12:34:39 +02002825 struct mgmt_ev_connected ev;
Sunny Kapdi93bef892012-07-30 14:52:56 -07002826 struct pending_cmd *cmd;
2827 struct hci_dev *hdev;
2828
2829 BT_DBG("hci%u", index);
2830
2831 hdev = hci_dev_get(index);
2832
2833 if (!hdev)
2834 return -ENODEV;
Johan Hedbergca69b792011-11-11 18:10:00 +02002835
Johan Hedbergf7520542011-01-20 12:34:39 +02002836 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002837 ev.le = le;
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002838
Sunny Kapdi93bef892012-07-30 14:52:56 -07002839 cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
2840 if (cmd) {
2841 BT_ERR("mgmt_connected remove mgmt pending white_list");
2842 mgmt_pending_remove(cmd);
2843 }
2844
Szymon Janc4e51eae2011-02-25 19:05:48 +01002845 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002846}
2847
Sunny Kapdia42b5022012-07-05 22:48:31 -07002848int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
2849 u16 latency, u16 timeout)
2850{
2851 struct mgmt_ev_le_conn_params ev;
2852
2853 bacpy(&ev.bdaddr, bdaddr);
2854 ev.interval = interval;
2855 ev.latency = latency;
2856 ev.timeout = timeout;
2857
2858 return mgmt_event(MGMT_EV_LE_CONN_PARAMS, index, &ev, sizeof(ev),
2859 NULL);
2860}
2861
Johan Hedberg8962ee72011-01-20 12:40:27 +02002862static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2863{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002864 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002865 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002866 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002867
Johan Hedberga38528f2011-01-22 06:46:43 +02002868 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002869
Szymon Janc4e51eae2011-02-25 19:05:48 +01002870 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002871
2872 *sk = cmd->sk;
2873 sock_hold(*sk);
2874
Johan Hedberga664b5b2011-02-19 12:06:02 -03002875 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002876}
2877
Archana Ramachandranda09d262012-08-14 12:03:01 -07002878int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002879{
Johan Hedbergf7520542011-01-20 12:34:39 +02002880 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002881 struct sock *sk = NULL;
2882 int err;
2883
Johan Hedbergf7520542011-01-20 12:34:39 +02002884 bacpy(&ev.bdaddr, bdaddr);
Archana Ramachandranda09d262012-08-14 12:03:01 -07002885 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02002886
Szymon Janc4e51eae2011-02-25 19:05:48 +01002887 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002888
2889 if (sk)
2890 sock_put(sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002891
Archana Ramachandranda09d262012-08-14 12:03:01 -07002892 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
2893
Johan Hedberg8962ee72011-01-20 12:40:27 +02002894 return err;
2895}
2896
2897int mgmt_disconnect_failed(u16 index)
2898{
2899 struct pending_cmd *cmd;
2900 int err;
2901
2902 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2903 if (!cmd)
2904 return -ENOENT;
2905
Szymon Janc4e51eae2011-02-25 19:05:48 +01002906 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002907
Johan Hedberga664b5b2011-02-19 12:06:02 -03002908 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002909
2910 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002911}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002912
2913int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2914{
2915 struct mgmt_ev_connect_failed ev;
2916
Johan Hedberg17d5c042011-01-22 06:09:08 +02002917 bacpy(&ev.bdaddr, bdaddr);
2918 ev.status = status;
2919
Szymon Janc4e51eae2011-02-25 19:05:48 +01002920 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002921}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002924{
2925 struct mgmt_ev_pin_code_request ev;
2926
Brian Gixa68668b2011-08-11 15:49:36 -07002927 BT_DBG("hci%u", index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002928
Johan Hedberg980e1a52011-01-22 06:10:07 +02002929 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002930 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002931
Szymon Janc4e51eae2011-02-25 19:05:48 +01002932 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2933 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002934}
2935
2936int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2937{
2938 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002939 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002940 int err;
2941
2942 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2943 if (!cmd)
2944 return -ENOENT;
2945
Johan Hedbergac56fb12011-02-19 12:05:59 -03002946 bacpy(&rp.bdaddr, bdaddr);
2947 rp.status = status;
2948
Szymon Janc4e51eae2011-02-25 19:05:48 +01002949 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2950 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002951
Johan Hedberga664b5b2011-02-19 12:06:02 -03002952 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002953
2954 return err;
2955}
2956
2957int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2958{
2959 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002960 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002961 int err;
2962
2963 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2964 if (!cmd)
2965 return -ENOENT;
2966
Johan Hedbergac56fb12011-02-19 12:05:59 -03002967 bacpy(&rp.bdaddr, bdaddr);
2968 rp.status = status;
2969
Szymon Janc4e51eae2011-02-25 19:05:48 +01002970 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2971 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002972
Johan Hedberga664b5b2011-02-19 12:06:02 -03002973 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002974
2975 return err;
2976}
Johan Hedberga5c29682011-02-19 12:05:57 -03002977
Brian Gixa68668b2011-08-11 15:49:36 -07002978int mgmt_user_confirm_request(u16 index, u8 event,
2979 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002980{
2981 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002982 struct hci_conn *conn = NULL;
2983 struct hci_dev *hdev;
2984 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
Johan Hedberga5c29682011-02-19 12:05:57 -03002985
Brian Gixa68668b2011-08-11 15:49:36 -07002986 BT_DBG("hci%u", index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002987
Brian Gixa68668b2011-08-11 15:49:36 -07002988 hdev = hci_dev_get(index);
2989
Brian Gix64bd5302011-09-08 11:35:48 -07002990 if (!hdev)
2991 return -ENODEV;
2992
Brian Gix64bd5302011-09-08 11:35:48 -07002993 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002994
2995 ev.auto_confirm = 0;
2996
2997 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2998 goto no_auto_confirm;
2999
3000 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
3001 rem_cap = conn->remote_cap;
3002 loc_mitm = conn->auth_type & 0x01;
3003 rem_mitm = conn->remote_auth & 0x01;
3004
Brian Gixdbf59292011-11-11 15:45:17 -08003005 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
3006 conn->auth_initiator && rem_cap == 0x03)
3007 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303008 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
3009 if (!loc_mitm && !rem_mitm)
3010 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07003011 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05303012 }
Brian Gixa68668b2011-08-11 15:49:36 -07003013
3014
3015 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
3016 ev.auto_confirm = 1;
3017
3018no_auto_confirm:
3019 bacpy(&ev.bdaddr, bdaddr);
3020 ev.event = event;
Johan Hedberga5c29682011-02-19 12:05:57 -03003021 put_unaligned_le32(value, &ev.value);
3022
Brian Gix64bd5302011-09-08 11:35:48 -07003023 hci_dev_put(hdev);
3024
Brian Gixa68668b2011-08-11 15:49:36 -07003025 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
3026 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003027}
3028
Brian Gixa68668b2011-08-11 15:49:36 -07003029int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
Brian Gix604086b2011-11-23 08:28:33 -08003030{
3031 struct mgmt_ev_user_passkey_request ev;
3032
Johan Hedberga5c29682011-02-19 12:05:57 -03003033 BT_DBG("hci%u", index);
Brian Gix604086b2011-11-23 08:28:33 -08003034
Johan Hedberga5c29682011-02-19 12:05:57 -03003035 bacpy(&ev.bdaddr, bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003036
Brian Gixa68668b2011-08-11 15:49:36 -07003037 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Johan Hedberga5c29682011-02-19 12:05:57 -03003038 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003039}
3040
Johan Hedberga5c29682011-02-19 12:05:57 -03003041static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
3042 u8 opcode)
3043{
3044 struct pending_cmd *cmd;
3045 struct mgmt_rp_user_confirm_reply rp;
3046 int err;
3047
3048 cmd = mgmt_pending_find(opcode, index);
3049 if (!cmd)
3050 return -ENOENT;
3051
Johan Hedberga5c29682011-02-19 12:05:57 -03003052 bacpy(&rp.bdaddr, bdaddr);
3053 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003054 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003055
Johan Hedberga664b5b2011-02-19 12:06:02 -03003056 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003057
3058 return err;
3059}
3060
3061int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
3062{
3063 return confirm_reply_complete(index, bdaddr, status,
3064 MGMT_OP_USER_CONFIRM_REPLY);
3065}
3066
Szymon Jancb8534e0f2011-03-01 16:55:34 +01003067int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003068{
3069 return confirm_reply_complete(index, bdaddr, status,
3070 MGMT_OP_USER_CONFIRM_NEG_REPLY);
3071}
Johan Hedberg2a611692011-02-19 12:06:00 -03003072
3073int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
3074{
3075 struct mgmt_ev_auth_failed ev;
3076
Johan Hedberg2a611692011-02-19 12:06:00 -03003077 bacpy(&ev.bdaddr, bdaddr);
3078 ev.status = status;
3079
Szymon Janc4e51eae2011-02-25 19:05:48 +01003080 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003081}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003082
3083int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
3084{
3085 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003086 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003087 struct mgmt_cp_set_local_name ev;
3088 int err;
3089
3090 memset(&ev, 0, sizeof(ev));
3091 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3092
3093 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
3094 if (!cmd)
3095 goto send_event;
3096
3097 if (status) {
3098 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
3099 goto failed;
3100 }
3101
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003102 hdev = hci_dev_get(index);
3103 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003104 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003105 hci_dev_put(hdev);
3106 }
3107
Johan Hedbergb312b1612011-03-16 14:29:37 +02003108 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
3109 sizeof(ev));
3110 if (err < 0)
3111 goto failed;
3112
3113send_event:
3114 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
3115 cmd ? cmd->sk : NULL);
3116
3117failed:
3118 if (cmd)
3119 mgmt_pending_remove(cmd);
3120 return err;
3121}
Szymon Jancc35938b2011-03-22 13:12:21 +01003122
3123int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
3124 u8 status)
3125{
3126 struct pending_cmd *cmd;
3127 int err;
3128
3129 BT_DBG("hci%u status %u", index, status);
3130
3131 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
3132 if (!cmd)
3133 return -ENOENT;
3134
3135 if (status) {
3136 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3137 EIO);
3138 } else {
3139 struct mgmt_rp_read_local_oob_data rp;
3140
3141 memcpy(rp.hash, hash, sizeof(rp.hash));
3142 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3143
3144 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
3145 &rp, sizeof(rp));
3146 }
3147
3148 mgmt_pending_remove(cmd);
3149
3150 return err;
3151}
Johan Hedberge17acd42011-03-30 23:57:16 +03003152
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003153void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
3154 u16 handle, u8 status)
Johan Hedberg06199cf2012-02-22 16:37:11 +02003155{
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003156 struct mgmt_ev_rssi_update ev;
3157 struct hci_conn *conn;
3158 struct hci_dev *hdev;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003159
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003160 if (status)
3161 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003162
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003163 hdev = hci_dev_get(index);
3164 conn = hci_conn_hash_lookup_handle(hdev, handle);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003165
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003166 if (!conn)
3167 return;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003168
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003169 BT_DBG("rssi_update_thresh_exceed : %d ",
3170 conn->rssi_update_thresh_exceed);
3171 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
3172 conn->rssi_threshold, rssi);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003173
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003174 if (conn->rssi_update_thresh_exceed == 1) {
3175 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003176 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003177 memset(&ev, 0, sizeof(ev));
3178 bacpy(&ev.bdaddr, bdaddr);
3179 ev.rssi = rssi;
3180 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3181 sizeof(ev), NULL);
3182 } else {
3183 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3184 conn->rssi_update_interval,
3185 conn->rssi_update_thresh_exceed);
3186 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003187 } else {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003188 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07003189 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003190 memset(&ev, 0, sizeof(ev));
3191 bacpy(&ev.bdaddr, bdaddr);
3192 ev.rssi = rssi;
3193 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
3194 sizeof(ev), NULL);
3195 } else {
3196 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
3197 conn->rssi_update_interval,
3198 conn->rssi_update_thresh_exceed);
3199 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003200 }
Johan Hedberg06199cf2012-02-22 16:37:11 +02003201}
3202
Archana Ramachandran26a752b2011-12-20 11:27:40 -08003203
Brian Gixa68668b2011-08-11 15:49:36 -07003204int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
3205 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03003206{
3207 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08003208 struct hci_dev *hdev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003209 int err;
3210
Brian Gixa68668b2011-08-11 15:49:36 -07003211 BT_DBG("le: %d", le);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003212
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003213 memset(&ev, 0, sizeof(ev));
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003214
Johan Hedberge17acd42011-03-30 23:57:16 +03003215 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03003216 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07003217 ev.type = type;
3218 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03003219
Brian Gixa68668b2011-08-11 15:49:36 -07003220 if (dev_class)
3221 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03003222
Brian Gixa68668b2011-08-11 15:49:36 -07003223 if (eir && eir_len)
3224 memcpy(ev.eir, eir, eir_len);
3225
3226 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
3227
3228 if (err < 0)
3229 return err;
3230
Brian Gix568dde92012-01-11 16:18:04 -08003231 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07003232
Brian Gix568dde92012-01-11 16:18:04 -08003233 if (!hdev)
3234 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003235
Brian Gix568dde92012-01-11 16:18:04 -08003236 if (hdev->disco_state == SCAN_IDLE)
3237 goto done;
3238
3239 hdev->disco_int_count++;
3240
3241 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3242 /* Inquiry scan for General Discovery LAP */
3243 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3244 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3245
3246 hdev->disco_int_phase *= 2;
3247 hdev->disco_int_count = 0;
3248 if (hdev->disco_state == SCAN_LE) {
3249 /* cancel LE scan */
3250 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3251 sizeof(le_cp), &le_cp);
3252 /* start BR scan */
3253 cp.num_rsp = (u8) hdev->disco_int_phase;
3254 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3255 sizeof(cp), &cp);
3256 hdev->disco_state = SCAN_BR;
3257 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003258 }
3259 }
3260
Brian Gix568dde92012-01-11 16:18:04 -08003261done:
3262 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003263 return 0;
Johan Hedberg314b2382011-04-27 10:29:57 -04003264}
Antti Julku5e762442011-08-25 16:48:02 +03003265
Brian Gixa68668b2011-08-11 15:49:36 -07003266
3267int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Antti Julku5e762442011-08-25 16:48:02 +03003268{
Johan Hedberga88a9652011-03-30 13:18:12 +03003269 struct mgmt_ev_remote_name ev;
Antti Julku5e762442011-08-25 16:48:02 +03003270
Johan Hedberga88a9652011-03-30 13:18:12 +03003271 memset(&ev, 0, sizeof(ev));
Antti Julku5e762442011-08-25 16:48:02 +03003272
Johan Hedberga88a9652011-03-30 13:18:12 +03003273 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003274 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003275 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Antti Julku5e762442011-08-25 16:48:02 +03003276
Johan Hedberga88a9652011-03-30 13:18:12 +03003277 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003278}
3279
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303280int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
Antti Julku5e762442011-08-25 16:48:02 +03003281{
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303282 struct mgmt_ev_encrypt_change ev;
Antti Julku5e762442011-08-25 16:48:02 +03003283
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303284 BT_DBG("hci%u", index);
Antti Julku5e762442011-08-25 16:48:02 +03003285
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303286 bacpy(&ev.bdaddr, bdaddr);
3287 ev.status = status;
Antti Julku5e762442011-08-25 16:48:02 +03003288
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303289 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3290 NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003291}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003292
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303293int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3294{
3295 struct mgmt_ev_remote_class ev;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003296
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303297 memset(&ev, 0, sizeof(ev));
3298
3299 bacpy(&ev.bdaddr, bdaddr);
3300 memcpy(ev.dev_class, dev_class, 3);
3301
3302 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3303}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303304
3305int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3306 u16 sub_ver)
3307{
3308 struct mgmt_ev_remote_version ev;
3309
3310 memset(&ev, 0, sizeof(ev));
3311
3312 bacpy(&ev.bdaddr, bdaddr);
3313 ev.lmp_ver = ver;
3314 ev.manufacturer = mnf;
3315 ev.lmp_subver = sub_ver;
3316
3317 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3318}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003319
3320int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3321{
3322 struct mgmt_ev_remote_features ev;
3323
3324 memset(&ev, 0, sizeof(ev));
3325
3326 bacpy(&ev.bdaddr, bdaddr);
3327 memcpy(ev.features, features, sizeof(ev.features));
3328
3329 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3330 NULL);
3331}