blob: bcd0dd77ac337d6a20fb98f0c6d05f811c802487 [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>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070031#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020032#include <net/bluetooth/mgmt.h>
Brian Gixa68668b2011-08-11 15:49:36 -070033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Brian Gix568dde92012-01-11 16:18:04 -080038#define SCAN_IDLE 0x00
39#define SCAN_LE 0x01
40#define SCAN_BR 0x02
Brian Gixa68668b2011-08-11 15:49:36 -070041
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042struct pending_cmd {
43 struct list_head list;
44 __u16 opcode;
45 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010046 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030048 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049};
50
Mat Martineau8cd0df02011-08-23 16:23:36 -070051struct mgmt_pending_free_work {
52 struct work_struct work;
53 struct sock *sk;
54};
55
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057
Szymon Janc4e51eae2011-02-25 19:05:48 +010058static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020059{
60 struct sk_buff *skb;
61 struct mgmt_hdr *hdr;
62 struct mgmt_ev_cmd_status *ev;
63
Szymon Janc34eb5252011-02-28 14:10:08 +010064 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020065
66 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
67 if (!skb)
68 return -ENOMEM;
69
70 hdr = (void *) skb_put(skb, sizeof(*hdr));
71
72 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010073 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020074 hdr->len = cpu_to_le16(sizeof(*ev));
75
76 ev = (void *) skb_put(skb, sizeof(*ev));
77 ev->status = status;
78 put_unaligned_le16(cmd, &ev->opcode);
79
80 if (sock_queue_rcv_skb(sk, skb) < 0)
81 kfree_skb(skb);
82
83 return 0;
84}
85
Szymon Janc4e51eae2011-02-25 19:05:48 +010086static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
87 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020088{
89 struct sk_buff *skb;
90 struct mgmt_hdr *hdr;
91 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020092
93 BT_DBG("sock %p", sk);
94
Johan Hedberga38528f2011-01-22 06:46:43 +020095 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020096 if (!skb)
97 return -ENOMEM;
98
99 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200100
Johan Hedberg02d98122010-12-13 21:07:04 +0200101 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100102 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200103 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200104
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
106 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100107
108 if (rp)
109 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200110
111 if (sock_queue_rcv_skb(sk, skb) < 0)
112 kfree_skb(skb);
113
114 return 0;
115}
116
Johan Hedberga38528f2011-01-22 06:46:43 +0200117static int read_version(struct sock *sk)
118{
119 struct mgmt_rp_read_version rp;
120
121 BT_DBG("sock %p", sk);
122
123 rp.version = MGMT_VERSION;
124 put_unaligned_le16(MGMT_REVISION, &rp.revision);
125
Szymon Janc4e51eae2011-02-25 19:05:48 +0100126 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
127 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200128}
129
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130static int read_index_list(struct sock *sk)
131{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132 struct mgmt_rp_read_index_list *rp;
133 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200134 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137
138 BT_DBG("sock %p", sk);
139
140 read_lock(&hci_dev_list_lock);
141
142 count = 0;
143 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700144 struct hci_dev *d = list_entry(p, struct hci_dev, list);
145 if (d->dev_type != HCI_BREDR)
146 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147 count++;
148 }
149
Johan Hedberga38528f2011-01-22 06:46:43 +0200150 rp_len = sizeof(*rp) + (2 * count);
151 rp = kmalloc(rp_len, GFP_ATOMIC);
152 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100153 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200154 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156
Brian Gixa68668b2011-08-11 15:49:36 -0700157 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
159 i = 0;
160 list_for_each(p, &hci_dev_list) {
161 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200162
163 hci_del_off_timer(d);
164
Peter Krystad1fc44072011-08-30 15:38:12 -0700165 if (d->dev_type != HCI_BREDR)
166 continue;
167
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200168 set_bit(HCI_MGMT, &d->flags);
169
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200170 if (test_bit(HCI_SETUP, &d->flags))
171 continue;
172
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200173 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700174 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200175 BT_DBG("Added hci%u", d->id);
176 }
177
178 read_unlock(&hci_dev_list_lock);
179
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
181 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183 kfree(rp);
184
185 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200186}
187
Szymon Janc4e51eae2011-02-25 19:05:48 +0100188static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200189{
Johan Hedberga38528f2011-01-22 06:46:43 +0200190 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200191 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200192
Szymon Janc4e51eae2011-02-25 19:05:48 +0100193 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200199 hci_del_off_timer(hdev);
200
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800201 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200203 set_bit(HCI_MGMT, &hdev->flags);
204
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200205 memset(&rp, 0, sizeof(rp));
206
Johan Hedberga38528f2011-01-22 06:46:43 +0200207 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Johan Hedberga38528f2011-01-22 06:46:43 +0200209 rp.powered = test_bit(HCI_UP, &hdev->flags);
210 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
211 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
212 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213
214 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200215 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200216 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220
Johan Hedberga38528f2011-01-22 06:46:43 +0200221 bacpy(&rp.bdaddr, &hdev->bdaddr);
222 memcpy(rp.features, hdev->features, 8);
223 memcpy(rp.dev_class, hdev->dev_class, 3);
224 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
225 rp.hci_ver = hdev->hci_ver;
226 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200227
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200228 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
229
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800230 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200232
Szymon Janc4e51eae2011-02-25 19:05:48 +0100233 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200234}
235
Mat Martineau8cd0df02011-08-23 16:23:36 -0700236static void mgmt_pending_free_worker(struct work_struct *work)
237{
238 struct mgmt_pending_free_work *free_work =
239 container_of(work, struct mgmt_pending_free_work, work);
240
241 BT_DBG("sk %p", free_work->sk);
242
243 sock_put(free_work->sk);
244 kfree(free_work);
245}
246
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200247static void mgmt_pending_free(struct pending_cmd *cmd)
248{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700249 struct mgmt_pending_free_work *free_work;
250 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700251
Mat Martineau8cd0df02011-08-23 16:23:36 -0700252 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
253
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100254 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200255 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700256
257 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
258 if (free_work) {
259 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
260 free_work->sk = sk;
261
262 if (!schedule_work(&free_work->work))
263 kfree(free_work);
264 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200265}
266
Johan Hedberg366a0332011-02-19 12:05:55 -0300267static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
268 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200269{
270 struct pending_cmd *cmd;
271
Brian Gixa68668b2011-08-11 15:49:36 -0700272 BT_DBG("%d", opcode);
273
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200274 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
275 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300276 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200277
278 cmd->opcode = opcode;
279 cmd->index = index;
280
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100281 cmd->param = kmalloc(len, GFP_ATOMIC);
282 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200283 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300284 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200285 }
286
Szymon Janc8fce6352011-03-22 13:12:20 +0100287 if (data)
288 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200289
290 cmd->sk = sk;
291 sock_hold(sk);
292
293 list_add(&cmd->list, &cmd_list);
294
Johan Hedberg366a0332011-02-19 12:05:55 -0300295 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200296}
297
298static void mgmt_pending_foreach(u16 opcode, int index,
299 void (*cb)(struct pending_cmd *cmd, void *data),
300 void *data)
301{
302 struct list_head *p, *n;
303
Brian Gixa68668b2011-08-11 15:49:36 -0700304 BT_DBG(" %d", opcode);
305
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306 list_for_each_safe(p, n, &cmd_list) {
307 struct pending_cmd *cmd;
308
309 cmd = list_entry(p, struct pending_cmd, list);
310
311 if (cmd->opcode != opcode)
312 continue;
313
314 if (index >= 0 && cmd->index != index)
315 continue;
316
317 cb(cmd, data);
318 }
319}
320
321static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
322{
323 struct list_head *p;
324
Brian Gixa68668b2011-08-11 15:49:36 -0700325 BT_DBG(" %d", opcode);
326
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200327 list_for_each(p, &cmd_list) {
328 struct pending_cmd *cmd;
329
330 cmd = list_entry(p, struct pending_cmd, list);
331
332 if (cmd->opcode != opcode)
333 continue;
334
335 if (index >= 0 && cmd->index != index)
336 continue;
337
338 return cmd;
339 }
340
341 return NULL;
342}
343
Johan Hedberga664b5b2011-02-19 12:06:02 -0300344static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200345{
Brian Gixa68668b2011-08-11 15:49:36 -0700346 BT_DBG(" %d", cmd->opcode);
347
Johan Hedberg73f22f62010-12-29 16:00:25 +0200348 list_del(&cmd->list);
349 mgmt_pending_free(cmd);
350}
351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200353{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200354 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200355 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300356 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200358
359 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200360
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200362
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100363 if (len != sizeof(*cp))
364 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200367 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200369
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800370 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200371
372 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200373 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375 goto failed;
376 }
377
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
379 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200380 goto failed;
381 }
382
Szymon Janc4e51eae2011-02-25 19:05:48 +0100383 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300384 if (!cmd) {
385 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200386 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300387 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200388
Johan Hedberg72a734e2010-12-30 00:38:22 +0200389 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200390 queue_work(hdev->workqueue, &hdev->power_on);
391 else
392 queue_work(hdev->workqueue, &hdev->power_off);
393
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200395
396failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800397 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300399 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200400}
401
Brian Gix8a7f1642011-10-17 17:39:46 -0700402static u8 get_service_classes(struct hci_dev *hdev)
403{
404 struct list_head *p;
405 u8 val = 0;
406
407 list_for_each(p, &hdev->uuids) {
408 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
409
410 val |= uuid->svc_hint;
411 }
412
413 return val;
414}
415
416static int update_class(struct hci_dev *hdev)
417{
418 u8 cod[3];
419
420 BT_DBG("%s", hdev->name);
421
422 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
423 return 0;
424
425 cod[0] = hdev->minor_class;
426 cod[1] = hdev->major_class;
427 cod[2] = get_service_classes(hdev);
428
429 if (memcmp(cod, hdev->dev_class, 3) == 0)
430 return 0;
431
432 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
433}
434
435static int set_limited_discoverable(struct sock *sk, u16 index,
436 unsigned char *data, u16 len)
437{
438 struct mgmt_mode *cp;
439 struct hci_dev *hdev;
440 struct pending_cmd *cmd;
441 struct hci_cp_write_current_iac_lap dcp;
442 int update_cod;
443 int err = 0;
444 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
445 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
446
447 cp = (void *) data;
448
449 BT_DBG("hci%u discoverable: %d", index, cp->val);
450
451 if (!cp || len != sizeof(*cp))
452 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
453 EINVAL);
454
455 hdev = hci_dev_get(index);
456 if (!hdev)
457 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
458 ENODEV);
459
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800460 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700461
462 if (!test_bit(HCI_UP, &hdev->flags)) {
463 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
464 ENETDOWN);
465 goto failed;
466 }
467
468 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
469 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
470 EBUSY);
471 goto failed;
472 }
473
474 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
475 test_bit(HCI_PSCAN, &hdev->flags)) {
476 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
477 EALREADY);
478 goto failed;
479 }
480
481 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
482 len);
483 if (!cmd) {
484 err = -ENOMEM;
485 goto failed;
486 }
487
488 memset(&dcp, 0, sizeof(dcp));
489 dcp.num_current_iac = cp->val ? 2 : 1;
490 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
491 update_cod = 1;
492
493 if (cp->val) {
494 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
495 update_cod = 0;
496 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
497 } else {
498 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
499 update_cod = 0;
500 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
501 }
502
503 if (update_cod)
504 err = update_class(hdev);
505
506 if (err >= 0)
507 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
508 sizeof(dcp), &dcp);
509
510 if (err < 0)
511 mgmt_pending_remove(cmd);
512
513failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800514 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700515 hci_dev_put(hdev);
516
517 return err;
518}
519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
521 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200522{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200523 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200524 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300525 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200526 u8 scan;
527 int err;
528
529 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200530
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200532
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100533 if (len != sizeof(*cp))
534 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
535
Szymon Janc4e51eae2011-02-25 19:05:48 +0100536 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200537 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200539
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800540 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200541
542 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100543 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200544 goto failed;
545 }
546
Szymon Janc4e51eae2011-02-25 19:05:48 +0100547 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
548 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
549 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200550 goto failed;
551 }
552
Johan Hedberg72a734e2010-12-30 00:38:22 +0200553 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200554 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100555 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200556 goto failed;
557 }
558
Szymon Janc4e51eae2011-02-25 19:05:48 +0100559 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300560 if (!cmd) {
561 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200562 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300563 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200564
565 scan = SCAN_PAGE;
566
Johan Hedberg72a734e2010-12-30 00:38:22 +0200567 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200568 scan |= SCAN_INQUIRY;
569
570 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
571 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300572 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200573
574failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800575 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200576 hci_dev_put(hdev);
577
578 return err;
579}
580
Szymon Janc4e51eae2011-02-25 19:05:48 +0100581static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
582 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200583{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200584 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200585 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300586 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200587 u8 scan;
588 int err;
589
590 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200591
Szymon Janc4e51eae2011-02-25 19:05:48 +0100592 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200593
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100594 if (len != sizeof(*cp))
595 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
596
Szymon Janc4e51eae2011-02-25 19:05:48 +0100597 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200598 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100599 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200600
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800601 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200602
603 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100604 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200605 goto failed;
606 }
607
Szymon Janc4e51eae2011-02-25 19:05:48 +0100608 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
609 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
610 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200611 goto failed;
612 }
613
Johan Hedberg72a734e2010-12-30 00:38:22 +0200614 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100615 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200616 goto failed;
617 }
618
Szymon Janc4e51eae2011-02-25 19:05:48 +0100619 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300620 if (!cmd) {
621 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200622 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300623 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200624
Johan Hedberg72a734e2010-12-30 00:38:22 +0200625 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200626 scan = SCAN_PAGE;
627 else
628 scan = 0;
629
630 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
631 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300632 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200633
634failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800635 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200636 hci_dev_put(hdev);
637
638 return err;
639}
640
Szymon Janc4e51eae2011-02-25 19:05:48 +0100641static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
642 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200643{
644 struct sk_buff *skb;
645 struct mgmt_hdr *hdr;
646
Brian Gixa68668b2011-08-11 15:49:36 -0700647 BT_DBG("hci%d %d", index, event);
648
Johan Hedbergc542a062011-01-26 13:11:03 +0200649 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
650 if (!skb)
651 return -ENOMEM;
652
653 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
654
655 hdr = (void *) skb_put(skb, sizeof(*hdr));
656 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100657 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200658 hdr->len = cpu_to_le16(data_len);
659
Szymon Janc4e51eae2011-02-25 19:05:48 +0100660 if (data)
661 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200662
663 hci_send_to_sock(NULL, skb, skip_sk);
664 kfree_skb(skb);
665
666 return 0;
667}
668
Johan Hedberg053f0212011-01-26 13:07:10 +0200669static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
670{
Johan Hedberga38528f2011-01-22 06:46:43 +0200671 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200672
Johan Hedberga38528f2011-01-22 06:46:43 +0200673 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200674
Szymon Janc4e51eae2011-02-25 19:05:48 +0100675 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200676}
677
Szymon Janc4e51eae2011-02-25 19:05:48 +0100678static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
679 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200680{
681 struct mgmt_mode *cp, ev;
682 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200683 int err;
684
685 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200686
Szymon Janc4e51eae2011-02-25 19:05:48 +0100687 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200688
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100689 if (len != sizeof(*cp))
690 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
691
Szymon Janc4e51eae2011-02-25 19:05:48 +0100692 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200693 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100694 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200695
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800696 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200697
698 if (cp->val)
699 set_bit(HCI_PAIRABLE, &hdev->flags);
700 else
701 clear_bit(HCI_PAIRABLE, &hdev->flags);
702
Szymon Janc4e51eae2011-02-25 19:05:48 +0100703 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200704 if (err < 0)
705 goto failed;
706
Johan Hedbergc542a062011-01-26 13:11:03 +0200707 ev.val = cp->val;
708
Szymon Janc4e51eae2011-02-25 19:05:48 +0100709 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200710
711failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800712 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200713 hci_dev_put(hdev);
714
715 return err;
716}
717
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300718#define EIR_FLAGS 0x01 /* flags */
719#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
720#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
721#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
722#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
723#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
724#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
725#define EIR_NAME_SHORT 0x08 /* shortened local name */
726#define EIR_NAME_COMPLETE 0x09 /* complete local name */
727#define EIR_TX_POWER 0x0A /* transmit power level */
728#define EIR_DEVICE_ID 0x10 /* device ID */
729
730#define PNP_INFO_SVCLASS_ID 0x1200
731
732static u8 bluetooth_base_uuid[] = {
733 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
734 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
735};
736
737static u16 get_uuid16(u8 *uuid128)
738{
739 u32 val;
740 int i;
741
742 for (i = 0; i < 12; i++) {
743 if (bluetooth_base_uuid[i] != uuid128[i])
744 return 0;
745 }
746
747 memcpy(&val, &uuid128[12], 4);
748
749 val = le32_to_cpu(val);
750 if (val > 0xffff)
751 return 0;
752
753 return (u16) val;
754}
755
756static void create_eir(struct hci_dev *hdev, u8 *data)
757{
758 u8 *ptr = data;
759 u16 eir_len = 0;
760 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
761 int i, truncated = 0;
762 struct list_head *p;
763 size_t name_len;
764
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530765 name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300766
767 if (name_len > 0) {
768 /* EIR Data type */
769 if (name_len > 48) {
770 name_len = 48;
771 ptr[1] = EIR_NAME_SHORT;
772 } else
773 ptr[1] = EIR_NAME_COMPLETE;
774
775 /* EIR Data length */
776 ptr[0] = name_len + 1;
777
778 memcpy(ptr + 2, hdev->dev_name, name_len);
779
780 eir_len += (name_len + 2);
781 ptr += (name_len + 2);
782 }
783
784 memset(uuid16_list, 0, sizeof(uuid16_list));
785
786 /* Group all UUID16 types */
787 list_for_each(p, &hdev->uuids) {
788 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
789 u16 uuid16;
790
791 uuid16 = get_uuid16(uuid->uuid);
792 if (uuid16 == 0)
793 return;
794
795 if (uuid16 < 0x1100)
796 continue;
797
798 if (uuid16 == PNP_INFO_SVCLASS_ID)
799 continue;
800
801 /* Stop if not enough space to put next UUID */
802 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
803 truncated = 1;
804 break;
805 }
806
807 /* Check for duplicates */
808 for (i = 0; uuid16_list[i] != 0; i++)
809 if (uuid16_list[i] == uuid16)
810 break;
811
812 if (uuid16_list[i] == 0) {
813 uuid16_list[i] = uuid16;
814 eir_len += sizeof(u16);
815 }
816 }
817
818 if (uuid16_list[0] != 0) {
819 u8 *length = ptr;
820
821 /* EIR Data type */
822 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
823
824 ptr += 2;
825 eir_len += 2;
826
827 for (i = 0; uuid16_list[i] != 0; i++) {
828 *ptr++ = (uuid16_list[i] & 0x00ff);
829 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
830 }
831
832 /* EIR Data length */
833 *length = (i * sizeof(u16)) + 1;
834 }
835}
836
837static int update_eir(struct hci_dev *hdev)
838{
839 struct hci_cp_write_eir cp;
840
841 if (!(hdev->features[6] & LMP_EXT_INQ))
842 return 0;
843
844 if (hdev->ssp_mode == 0)
845 return 0;
846
847 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
848 return 0;
849
850 memset(&cp, 0, sizeof(cp));
851
852 create_eir(hdev, cp.data);
853
854 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
855 return 0;
856
857 memcpy(hdev->eir, cp.data, sizeof(cp.data));
858
859 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
860}
861
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200863{
864 struct mgmt_cp_add_uuid *cp;
865 struct hci_dev *hdev;
866 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200867 int err;
868
869 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200872
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873 if (len != sizeof(*cp))
874 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200877 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200879
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800880 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881
882 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
883 if (!uuid) {
884 err = -ENOMEM;
885 goto failed;
886 }
887
888 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890
891 list_add(&uuid->list, &hdev->uuids);
892
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530893 if (test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200894
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530895 err = update_class(hdev);
896 if (err < 0)
897 goto failed;
898
899 err = update_eir(hdev);
900 if (err < 0)
901 goto failed;
902 } else
903 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300904
Szymon Janc4e51eae2011-02-25 19:05:48 +0100905 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200906
907failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800908 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200909 hci_dev_put(hdev);
910
911 return err;
912}
913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915{
916 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100917 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 struct hci_dev *hdev;
919 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 +0200920 int err, found;
921
922 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200923
Szymon Janc4e51eae2011-02-25 19:05:48 +0100924 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200925
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100926 if (len != sizeof(*cp))
927 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
928
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200930 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100931 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200932
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800933 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934
935 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
936 err = hci_uuids_clear(hdev);
937 goto unlock;
938 }
939
940 found = 0;
941
942 list_for_each_safe(p, n, &hdev->uuids) {
943 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
944
945 if (memcmp(match->uuid, cp->uuid, 16) != 0)
946 continue;
947
948 list_del(&match->list);
949 found++;
950 }
951
952 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100953 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200954 goto unlock;
955 }
956
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530957 if (test_bit(HCI_UP, &hdev->flags)) {
958 err = update_class(hdev);
959 if (err < 0)
960 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200961
Bhasker Netia6e6a4f2012-01-27 15:25:43 +0530962 err = update_eir(hdev);
963 if (err < 0)
964 goto unlock;
965 } else
966 err = 0;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300967
Szymon Janc4e51eae2011-02-25 19:05:48 +0100968 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200969
970unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800971 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200972 hci_dev_put(hdev);
973
974 return err;
975}
976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
978 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200979{
980 struct hci_dev *hdev;
981 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200982 int err;
983
984 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200985
Szymon Janc4e51eae2011-02-25 19:05:48 +0100986 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200987
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100988 if (len != sizeof(*cp))
989 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
990
Szymon Janc4e51eae2011-02-25 19:05:48 +0100991 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200992 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100993 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800995 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996
Brian Gix8a7f1642011-10-17 17:39:46 -0700997 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
998 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200999 hdev->minor_class = cp->minor;
1000
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301001 if (test_bit(HCI_UP, &hdev->flags))
1002 err = update_class(hdev);
1003 else
1004 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001005
1006 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001009 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001010 hci_dev_put(hdev);
1011
1012 return err;
1013}
1014
Szymon Janc4e51eae2011-02-25 19:05:48 +01001015static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1016 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017{
1018 struct hci_dev *hdev;
1019 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001020 int err;
1021
1022 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001023
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001024 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001025 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001026
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001028 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001030
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001031 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001034
1035 if (cp->enable) {
1036 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1037 err = 0;
1038 } else {
1039 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05301040 if (test_bit(HCI_UP, &hdev->flags)) {
1041 err = update_class(hdev);
1042 if (err == 0)
1043 err = update_eir(hdev);
1044 } else
1045 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001046 }
1047
1048 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001049 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1050 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001051
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001052 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001053 hci_dev_put(hdev);
1054
1055 return err;
1056}
1057
Szymon Janc4e51eae2011-02-25 19:05:48 +01001058static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001059{
1060 struct hci_dev *hdev;
1061 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001062 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001063 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001064
1065 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001066
1067 if (len < sizeof(*cp))
1068 return -EINVAL;
1069
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001070 key_count = get_unaligned_le16(&cp->key_count);
1071
1072 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001073 if (expected_len > len) {
1074 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1075 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001076 return -EINVAL;
1077 }
1078
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001082
Szymon Janc4e51eae2011-02-25 19:05:48 +01001083 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001084 key_count);
1085
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001086 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001087
1088 hci_link_keys_clear(hdev);
1089
1090 set_bit(HCI_LINK_KEYS, &hdev->flags);
1091
1092 if (cp->debug_keys)
1093 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1094 else
1095 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1096
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001097 len -= sizeof(*cp);
1098 i = 0;
1099
1100 while (i < len) {
1101 struct mgmt_key_info *key = (void *) cp->keys + i;
1102
Brian Gixa68668b2011-08-11 15:49:36 -07001103 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001104
Brian Gixcf956772011-10-20 15:18:51 -07001105 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001106 struct key_master_id *id = (void *) key->data;
1107
1108 if (key->dlen != sizeof(struct key_master_id))
1109 continue;
1110
Brian Gixcf956772011-10-20 15:18:51 -07001111 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1112 key->pin_len, key->auth, id->ediv,
1113 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001114
1115 continue;
1116 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001117
Brian Gixcf956772011-10-20 15:18:51 -07001118 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001119 key->pin_len);
1120 }
1121
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001122 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1123
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001124 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001125 hci_dev_put(hdev);
1126
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001127 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001128}
1129
Szymon Janc4e51eae2011-02-25 19:05:48 +01001130static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001131{
1132 struct hci_dev *hdev;
1133 struct mgmt_cp_remove_key *cp;
1134 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001135 int err;
1136
1137 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001138
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001139 if (len != sizeof(*cp))
1140 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1141
Szymon Janc4e51eae2011-02-25 19:05:48 +01001142 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001143 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001144 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001145
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001146 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001147
1148 err = hci_remove_link_key(hdev, &cp->bdaddr);
1149 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001150 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001151 goto unlock;
1152 }
1153
1154 err = 0;
1155
1156 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1157 goto unlock;
1158
1159 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1160 if (conn) {
1161 struct hci_cp_disconnect dc;
1162
1163 put_unaligned_le16(conn->handle, &dc.handle);
1164 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001166 }
1167
1168unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001169 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001170 hci_dev_put(hdev);
1171
1172 return err;
1173}
1174
Szymon Janc4e51eae2011-02-25 19:05:48 +01001175static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001176{
1177 struct hci_dev *hdev;
1178 struct mgmt_cp_disconnect *cp;
1179 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001181 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001182 int err;
1183
1184 BT_DBG("");
1185
1186 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001187
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001188 if (len != sizeof(*cp))
1189 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1190
Szymon Janc4e51eae2011-02-25 19:05:48 +01001191 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001192 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001193 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001195 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196
1197 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001199 goto failed;
1200 }
1201
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1203 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204 goto failed;
1205 }
1206
1207 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1208 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001209 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1210 if (!conn) {
1211 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1212 ENOTCONN);
1213 goto failed;
1214 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001215 }
1216
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001218 if (!cmd) {
1219 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001220 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001221 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001222
1223 put_unaligned_le16(conn->handle, &dc.handle);
1224 dc.reason = 0x13; /* Remote User Terminated Connection */
1225
1226 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1227 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001228 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001229
1230failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001231 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001232 hci_dev_put(hdev);
1233
1234 return err;
1235}
1236
Szymon Janc8ce62842011-03-01 16:55:32 +01001237static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001238{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001239 struct mgmt_rp_get_connections *rp;
1240 struct hci_dev *hdev;
1241 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001242 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 int i, err;
1245
1246 BT_DBG("");
1247
Szymon Janc4e51eae2011-02-25 19:05:48 +01001248 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001251
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001252 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253
1254 count = 0;
1255 list_for_each(p, &hdev->conn_hash.list) {
1256 count++;
1257 }
1258
Johan Hedberga38528f2011-01-22 06:46:43 +02001259 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1260 rp = kmalloc(rp_len, GFP_ATOMIC);
1261 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262 err = -ENOMEM;
1263 goto unlock;
1264 }
1265
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266 put_unaligned_le16(count, &rp->conn_count);
1267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 read_lock(&hci_dev_list_lock);
1269
Johan Hedberg2784eb42011-01-21 13:56:35 +02001270 i = 0;
1271 list_for_each(p, &hdev->conn_hash.list) {
1272 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1273
1274 bacpy(&rp->conn[i++], &c->dst);
1275 }
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 read_unlock(&hci_dev_list_lock);
1278
Szymon Janc4e51eae2011-02-25 19:05:48 +01001279 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001280
1281unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001282 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001283 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001284 hci_dev_put(hdev);
1285 return err;
1286}
1287
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1289 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001290{
1291 struct hci_dev *hdev;
1292 struct mgmt_cp_pin_code_reply *cp;
1293 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001294 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001295 int err;
1296
1297 BT_DBG("");
1298
1299 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001300
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001301 if (len != sizeof(*cp))
1302 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1303
Szymon Janc4e51eae2011-02-25 19:05:48 +01001304 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001305 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001307
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001308 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001309
1310 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001311 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001312 goto failed;
1313 }
1314
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001316 if (!cmd) {
1317 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001318 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001319 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320
1321 bacpy(&reply.bdaddr, &cp->bdaddr);
1322 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324
1325 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1326 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001327 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328
1329failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001330 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001331 hci_dev_put(hdev);
1332
1333 return err;
1334}
1335
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301336static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1337 u16 len)
1338{
1339 struct hci_dev *hdev;
1340 struct mgmt_cp_encrypt_link *cp;
1341 struct hci_cp_set_conn_encrypt enc;
1342 struct hci_conn *conn;
1343 int err = 0;
1344
1345 BT_DBG("");
1346
1347 cp = (void *) data;
1348
1349 if (len != sizeof(*cp))
1350 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1351
1352 hdev = hci_dev_get(index);
1353 if (!hdev)
1354 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1355
1356 hci_dev_lock(hdev);
1357
1358 if (!test_bit(HCI_UP, &hdev->flags)) {
1359 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
1360 goto failed;
1361 }
1362
1363 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1364 &cp->bdaddr);
1365 if (!conn)
1366 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1367
1368 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
1369 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1370
1371 if (conn->link_mode & HCI_LM_AUTH) {
1372 enc.handle = cpu_to_le16(conn->handle);
1373 enc.encrypt = cp->enable;
1374 err = hci_send_cmd(hdev,
1375 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1376 } else {
1377 conn->auth_initiator = 1;
1378 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1379 struct hci_cp_auth_requested cp;
1380 cp.handle = cpu_to_le16(conn->handle);
1381 err = hci_send_cmd(conn->hdev,
1382 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1383 }
1384 }
1385
1386failed:
1387 hci_dev_unlock(hdev);
1388 hci_dev_put(hdev);
1389
1390 return err;
1391}
1392
1393
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1395 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001396{
1397 struct hci_dev *hdev;
1398 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400 int err;
1401
1402 BT_DBG("");
1403
1404 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001405
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001406 if (len != sizeof(*cp))
1407 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1408 EINVAL);
1409
Szymon Janc4e51eae2011-02-25 19:05:48 +01001410 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001412 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1413 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001414
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001415 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001416
1417 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001418 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1419 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001420 goto failed;
1421 }
1422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1424 data, len);
1425 if (!cmd) {
1426 err = -ENOMEM;
1427 goto failed;
1428 }
1429
1430 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1431 &cp->bdaddr);
1432 if (err < 0)
1433 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001434
1435failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001436 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001437 hci_dev_put(hdev);
1438
1439 return err;
1440}
1441
Szymon Janc4e51eae2011-02-25 19:05:48 +01001442static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1443 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001444{
1445 struct hci_dev *hdev;
1446 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001447
1448 BT_DBG("");
1449
1450 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001451
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001452 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001453 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001454
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001456 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001458
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001459 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001460
1461 hdev->io_capability = cp->io_capability;
1462
1463 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001464 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001465
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001466 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001467 hci_dev_put(hdev);
1468
Szymon Janc4e51eae2011-02-25 19:05:48 +01001469 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001470}
1471
Johan Hedberge9a416b2011-02-19 12:05:56 -03001472static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1473{
1474 struct hci_dev *hdev = conn->hdev;
1475 struct list_head *p;
1476
1477 list_for_each(p, &cmd_list) {
1478 struct pending_cmd *cmd;
1479
1480 cmd = list_entry(p, struct pending_cmd, list);
1481
1482 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1483 continue;
1484
1485 if (cmd->index != hdev->id)
1486 continue;
1487
1488 if (cmd->user_data != conn)
1489 continue;
1490
1491 return cmd;
1492 }
1493
1494 return NULL;
1495}
1496
1497static void pairing_complete(struct pending_cmd *cmd, u8 status)
1498{
1499 struct mgmt_rp_pair_device rp;
1500 struct hci_conn *conn = cmd->user_data;
1501
Brian Gixa68668b2011-08-11 15:49:36 -07001502 BT_DBG(" %u", status);
1503
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504 bacpy(&rp.bdaddr, &conn->dst);
1505 rp.status = status;
1506
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508
1509 /* So we don't get further callbacks for this connection */
1510 conn->connect_cfm_cb = NULL;
1511 conn->security_cfm_cb = NULL;
1512 conn->disconn_cfm_cb = NULL;
1513
Johan Hedberga664b5b2011-02-19 12:06:02 -03001514 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001515}
1516
1517static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1518{
1519 struct pending_cmd *cmd;
1520
Brian Gixa68668b2011-08-11 15:49:36 -07001521 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001522
1523 cmd = find_pairing(conn);
1524 if (!cmd) {
1525 BT_DBG("Unable to find a pending command");
1526 return;
1527 }
1528
1529 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001530 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001531}
1532
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001533static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001534{
1535 struct pending_cmd *cmd;
1536
1537 BT_DBG(" %u", status);
1538
1539 cmd = find_pairing(conn);
1540 if (!cmd) {
1541 BT_DBG("Unable to find a pending command");
1542 return;
1543 }
1544
1545 if (conn->type == LE_LINK)
1546 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1547 status ? 0 : 1);
1548 else
1549 pairing_complete(cmd, status);
1550}
1551
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001552static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001553{
1554 struct pending_cmd *cmd;
1555
1556 BT_DBG("conn: %p %u", conn, status);
1557
1558 cmd = find_pairing(conn);
1559 if (!cmd) {
1560 BT_DBG("Unable to find a pending command");
1561 return;
1562 }
Brian Gix114f3a62011-09-27 14:02:20 -07001563
1564 if (status)
1565 pairing_complete(cmd, status);
1566
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001567 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001568}
1569
1570static void discovery_terminated(struct pending_cmd *cmd, void *data)
1571{
Brian Gix6e349d02011-11-28 14:51:14 -08001572 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001573 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001574
1575 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001576 hdev = hci_dev_get(cmd->index);
1577 if (!hdev)
1578 goto not_found;
1579
Brian Gix568dde92012-01-11 16:18:04 -08001580 del_timer(&hdev->disco_le_timer);
1581 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001582 hci_dev_put(hdev);
1583
1584not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001585 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1586
1587 list_del(&cmd->list);
1588
1589 mgmt_pending_free(cmd);
1590}
1591
Szymon Janc4e51eae2011-02-25 19:05:48 +01001592static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001593{
1594 struct hci_dev *hdev;
1595 struct mgmt_cp_pair_device *cp;
1596 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001597 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001598 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001599 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001600 int err;
1601
1602 BT_DBG("");
1603
Brian Gix64bd5302011-09-08 11:35:48 -07001604 cp = (void *) data;
1605
1606 if (len != sizeof(*cp))
1607 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1608
Szymon Janc4e51eae2011-02-25 19:05:48 +01001609 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001610
Johan Hedberge9a416b2011-02-19 12:05:56 -03001611 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001612 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001613
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001614 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001615
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301616 io_cap = cp->io_cap;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301617
1618 sec_level = BT_SECURITY_MEDIUM;
1619 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001620
Brian Gixfdd38922011-09-28 16:23:48 -07001621 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1622 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001623 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1624 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001625 } else {
1626 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1627 if (io_cap == 0x04)
1628 io_cap = 0x01;
1629 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1630 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301631 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001632 }
1633
Ville Tervo30e76272011-02-22 16:10:53 -03001634 if (IS_ERR(conn)) {
1635 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001636 goto unlock;
1637 }
1638
1639 if (conn->connect_cfm_cb) {
1640 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001641 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001642 goto unlock;
1643 }
1644
Szymon Janc4e51eae2011-02-25 19:05:48 +01001645 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001646 if (!cmd) {
1647 err = -ENOMEM;
1648 hci_conn_put(conn);
1649 goto unlock;
1650 }
1651
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001652 conn->connect_cfm_cb = pairing_connect_complete_cb;
1653 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001654 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001655 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001656 cmd->user_data = conn;
1657
1658 if (conn->state == BT_CONNECTED &&
1659 hci_conn_security(conn, sec_level, auth_type))
1660 pairing_complete(cmd, 0);
1661
1662 err = 0;
1663
1664unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001665 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001666 hci_dev_put(hdev);
1667
1668 return err;
1669}
1670
Szymon Janc4e51eae2011-02-25 19:05:48 +01001671static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001672 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001673{
1674 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001675 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001676 struct pending_cmd *cmd;
1677 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001678 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 int err;
1680
Brian Gixa68668b2011-08-11 15:49:36 -07001681 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001682
Brian Gixa68668b2011-08-11 15:49:36 -07001683 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001684 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001685 else
1686 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001687
Brian Gixa68668b2011-08-11 15:49:36 -07001688 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001689 return cmd_status(sk, index, mgmt_op, EINVAL);
1690
Szymon Janc4e51eae2011-02-25 19:05:48 +01001691 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001692 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001693 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001694
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001695 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001696
Johan Hedberga5c29682011-02-19 12:05:57 -03001697 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001698 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001699 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001700 }
1701
Brian Gixa68668b2011-08-11 15:49:36 -07001702 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1703 if (le_conn) {
1704 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1705 goto done;
1706 }
1707 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1708 "Reject" : "Accept");
1709
Szymon Janc4e51eae2011-02-25 19:05:48 +01001710 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001711 if (!cmd) {
1712 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001713 goto done;
1714 }
1715
1716 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1717 if (err < 0)
1718 mgmt_pending_remove(cmd);
1719
1720done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001721 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001722 hci_dev_put(hdev);
1723
1724 return err;
1725}
1726
1727static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1728 u16 len)
1729{
1730 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1731 struct hci_cp_remote_name_req hci_cp;
1732 struct hci_dev *hdev;
1733 struct pending_cmd *cmd;
1734 int err;
1735
1736 BT_DBG("");
1737
1738 if (len != sizeof(*mgmt_cp))
1739 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1740
1741 hdev = hci_dev_get(index);
1742 if (!hdev)
1743 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1744
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001745 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001746
1747 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1748 if (!cmd) {
1749 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001750 goto failed;
1751 }
1752
Brian Gixa68668b2011-08-11 15:49:36 -07001753 memset(&hci_cp, 0, sizeof(hci_cp));
1754 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1755 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1756 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001757 if (err < 0)
1758 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001759
1760failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001761 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001762 hci_dev_put(hdev);
1763
1764 return err;
1765}
1766
Brian Gix7f7e16c2011-11-01 16:27:25 -07001767static int set_connection_params(struct sock *sk, u16 index,
1768 unsigned char *data, u16 len)
1769{
1770 struct mgmt_cp_set_connection_params *cp = (void *) data;
1771 struct hci_dev *hdev;
1772 struct hci_conn *conn;
1773 int err;
1774
1775 BT_DBG("");
1776
1777 if (len != sizeof(*cp))
1778 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1779 EINVAL);
1780
1781 hdev = hci_dev_get(index);
1782 if (!hdev)
1783 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1784 ENODEV);
1785
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001786 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001787
1788 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1789 if (!conn) {
1790 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1791 ENOTCONN);
1792 goto failed;
1793 }
1794
1795 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1796 le16_to_cpu(cp->interval_max),
1797 le16_to_cpu(cp->slave_latency),
1798 le16_to_cpu(cp->timeout_multiplier));
1799
1800 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1801
1802failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001803 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001804 hci_dev_put(hdev);
1805
1806 return err;
1807}
1808
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001809static int set_rssi_reporter(struct sock *sk, u16 index,
1810 unsigned char *data, u16 len)
1811{
1812 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
1813 struct hci_dev *hdev;
1814 struct hci_conn *conn;
1815 int err = 0;
1816
1817 if (len != sizeof(*cp))
1818 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1819 EINVAL);
1820
1821 hdev = hci_dev_get(index);
1822 if (!hdev)
1823 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1824 ENODEV);
1825
1826 hci_dev_lock(hdev);
1827
1828 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1829
1830 if (!conn) {
1831 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1832 ENOTCONN);
1833 goto failed;
1834 }
1835
1836 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
1837 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
1838 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
1839
1840failed:
1841 hci_dev_unlock(hdev);
1842 hci_dev_put(hdev);
1843
1844 return err;
1845}
1846
1847static int unset_rssi_reporter(struct sock *sk, u16 index,
1848 unsigned char *data, u16 len)
1849{
1850 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
1851 struct hci_dev *hdev;
1852 struct hci_conn *conn;
1853 int err = 0;
1854
1855 if (len != sizeof(*cp))
1856 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1857 EINVAL);
1858
1859 hdev = hci_dev_get(index);
1860
1861 if (!hdev)
1862 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1863 ENODEV);
1864
1865 hci_dev_lock(hdev);
1866
1867 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1868
1869 if (!conn) {
1870 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1871 ENOTCONN);
1872 goto failed;
1873 }
1874
1875 hci_conn_unset_rssi_reporter(conn);
1876
1877failed:
1878 hci_dev_unlock(hdev);
1879 hci_dev_put(hdev);
1880
1881 return err;
1882}
1883
Johan Hedbergb312b1612011-03-16 14:29:37 +02001884static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1885 u16 len)
1886{
1887 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1888 struct hci_cp_write_local_name hci_cp;
1889 struct hci_dev *hdev;
1890 struct pending_cmd *cmd;
1891 int err;
1892
1893 BT_DBG("");
1894
1895 if (len != sizeof(*mgmt_cp))
1896 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1897
1898 hdev = hci_dev_get(index);
1899 if (!hdev)
1900 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1901
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001902 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001903
1904 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1905 if (!cmd) {
1906 err = -ENOMEM;
1907 goto failed;
1908 }
1909
1910 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1911 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1912 &hci_cp);
1913 if (err < 0)
1914 mgmt_pending_remove(cmd);
1915
1916failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001917 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001918 hci_dev_put(hdev);
1919
1920 return err;
1921}
1922
Brian Gixa68668b2011-08-11 15:49:36 -07001923static void discovery_rsp(struct pending_cmd *cmd, void *data)
1924{
1925 struct mgmt_mode ev;
1926
1927 BT_DBG("");
1928 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1929 ev.val = 1;
1930 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1931 } else {
1932 ev.val = 0;
1933 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1934 NULL, 0);
1935 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001936 struct hci_dev *hdev = hci_dev_get(cmd->index);
1937 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08001938 del_timer(&hdev->disco_le_timer);
1939 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001940 hci_dev_put(hdev);
1941 }
Brian Gixa68668b2011-08-11 15:49:36 -07001942 }
1943 }
1944
1945 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1946
1947 list_del(&cmd->list);
1948
1949 mgmt_pending_free(cmd);
1950}
1951
1952void mgmt_inquiry_started(u16 index)
1953{
1954 BT_DBG("");
1955 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1956 discovery_rsp, NULL);
1957}
1958
1959void mgmt_inquiry_complete_evt(u16 index, u8 status)
1960{
1961 struct hci_dev *hdev;
1962 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08001963 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001964 int err = -1;
1965
1966 BT_DBG("");
1967
1968 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001969
Brian Gixa68668b2011-08-11 15:49:36 -07001970 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07001971
1972 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1973 discovery_terminated, NULL);
1974
1975 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001976
Brian Gix64bd5302011-09-08 11:35:48 -07001977 if (hdev)
1978 goto done;
1979 else
1980 return;
1981 }
Brian Gixa68668b2011-08-11 15:49:36 -07001982
Brian Gix568dde92012-01-11 16:18:04 -08001983 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07001984 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1985 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08001986 if (err >= 0) {
1987 mod_timer(&hdev->disco_le_timer, jiffies +
1988 msecs_to_jiffies(hdev->disco_int_phase * 1000));
1989 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07001990 } else
Brian Gix568dde92012-01-11 16:18:04 -08001991 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07001992 }
1993
Brian Gix568dde92012-01-11 16:18:04 -08001994 if (hdev->disco_state == SCAN_IDLE)
1995 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
1996
Brian Gixa68668b2011-08-11 15:49:36 -07001997 if (err < 0)
1998 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1999 discovery_terminated, NULL);
2000
Brian Gix64bd5302011-09-08 11:35:48 -07002001done:
Brian Gixa68668b2011-08-11 15:49:36 -07002002 hci_dev_put(hdev);
2003}
2004
Brian Gix568dde92012-01-11 16:18:04 -08002005void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002006{
Brian Gix568dde92012-01-11 16:18:04 -08002007 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002008 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002009 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002010
Brian Gix568dde92012-01-11 16:18:04 -08002011 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002012
Brian Gix568dde92012-01-11 16:18:04 -08002013 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002014
Brian Gix568dde92012-01-11 16:18:04 -08002015 if (!hdev)
2016 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002017
Brian Gix568dde92012-01-11 16:18:04 -08002018 hci_dev_lock_bh(hdev);
2019 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002020
Brian Gix568dde92012-01-11 16:18:04 -08002021 if (hdev->disco_state != SCAN_IDLE) {
2022 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002023
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302024 if (test_bit(HCI_UP, &hdev->flags)) {
2025 if (hdev->disco_state == SCAN_LE)
2026 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002027 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302028 else
2029 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2030 NULL);
2031 }
Brian Gix568dde92012-01-11 16:18:04 -08002032 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002033 }
Brian Gix568dde92012-01-11 16:18:04 -08002034
2035 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2036
2037 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2038 if (cmd)
2039 mgmt_pending_remove(cmd);
2040
2041 hci_dev_unlock_bh(hdev);
2042 hci_dev_put(hdev);
2043}
2044
2045void mgmt_disco_le_timeout(unsigned long data)
2046{
2047 struct hci_dev *hdev = (void *)data;
2048 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2049
2050 BT_DBG("hci%d", hdev->id);
2051
2052 hdev = hci_dev_get(hdev->id);
2053
2054 if (!hdev)
2055 return;
2056
2057 hci_dev_lock_bh(hdev);
2058
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302059 if (test_bit(HCI_UP, &hdev->flags)) {
2060 if (hdev->disco_state == SCAN_LE)
2061 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2062 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002063
2064 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302065 if (hdev->disco_state != SCAN_IDLE) {
2066 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2067 hdev->disco_int_phase *= 2;
2068 hdev->disco_int_count = 0;
2069 cp.num_rsp = (u8) hdev->disco_int_phase;
2070 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2071 hdev->disco_state = SCAN_BR;
2072 }
Brian Gix568dde92012-01-11 16:18:04 -08002073 }
2074
2075 hci_dev_unlock_bh(hdev);
2076 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002077}
2078
2079static int start_discovery(struct sock *sk, u16 index)
2080{
2081 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2082 struct hci_dev *hdev;
2083 struct pending_cmd *cmd;
2084 int err;
2085
2086 BT_DBG("");
2087
2088 hdev = hci_dev_get(index);
2089 if (!hdev)
2090 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2091
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002092 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002093
Brian Gix568dde92012-01-11 16:18:04 -08002094 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2095 err = -EBUSY;
2096 goto failed;
2097 }
2098
Brian Gixa68668b2011-08-11 15:49:36 -07002099 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2100 if (!cmd) {
2101 err = -ENOMEM;
2102 goto failed;
2103 }
2104
2105 /* If LE Capable, we will alternate between BR/EDR and LE */
2106 if (lmp_le_capable(hdev)) {
2107 struct hci_cp_le_set_scan_parameters le_cp;
2108
2109 /* Shorten BR scan params */
2110 cp.num_rsp = 1;
2111 cp.length /= 2;
2112
2113 /* Setup LE scan params */
2114 memset(&le_cp, 0, sizeof(le_cp));
2115 le_cp.type = 0x01; /* Active scanning */
2116 /* The recommended value for scan interval and window is
2117 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2118 le_cp.interval = cpu_to_le16(0x0012);
2119 le_cp.window = cpu_to_le16(0x0012);
2120 le_cp.own_bdaddr_type = 0; /* Public address */
2121 le_cp.filter = 0; /* Accept all adv packets */
2122
2123 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2124 sizeof(le_cp), &le_cp);
2125 }
2126
2127 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2128
2129 if (err < 0)
2130 mgmt_pending_remove(cmd);
2131 else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002132 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2133 if (!cmd)
2134 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2135 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002136 hdev->disco_int_phase = 1;
2137 hdev->disco_int_count = 0;
2138 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002139 del_timer(&hdev->disco_le_timer);
2140 del_timer(&hdev->disco_timer);
2141 mod_timer(&hdev->disco_timer,
2142 jiffies + msecs_to_jiffies(20000));
Brian Gixa68668b2011-08-11 15:49:36 -07002143 }
2144
2145failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002146 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002147 hci_dev_put(hdev);
2148
Brian Gix568dde92012-01-11 16:18:04 -08002149 if (err < 0)
2150 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2151
Brian Gixa68668b2011-08-11 15:49:36 -07002152 return err;
2153}
2154
2155static int stop_discovery(struct sock *sk, u16 index)
2156{
2157 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2158 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002159 struct hci_dev *hdev;
2160 struct pending_cmd *cmd = NULL;
2161 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002162 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002163
2164 BT_DBG("");
2165
2166 hdev = hci_dev_get(index);
2167 if (!hdev)
2168 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2169
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002170 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002171
Brian Gix568dde92012-01-11 16:18:04 -08002172 state = hdev->disco_state;
2173 hdev->disco_state = SCAN_IDLE;
2174 del_timer(&hdev->disco_le_timer);
2175 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002176
Brian Gix568dde92012-01-11 16:18:04 -08002177 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002178 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2179 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002180 if (err >= 0) {
2181 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2182 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002183
Brian Gix568dde92012-01-11 16:18:04 -08002184 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2185 NULL, 0);
2186 }
Brian Gixa68668b2011-08-11 15:49:36 -07002187 }
2188
Brian Gix568dde92012-01-11 16:18:04 -08002189 if (err < 0)
2190 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002191
Brian Gix568dde92012-01-11 16:18:04 -08002192 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002193 if (err < 0 && cmd)
2194 mgmt_pending_remove(cmd);
2195
2196 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2197
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002198 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002199 hci_dev_put(hdev);
2200
2201 if (err < 0)
2202 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2203 else
2204 return err;
2205}
2206
Szymon Jancc35938b2011-03-22 13:12:21 +01002207static int read_local_oob_data(struct sock *sk, u16 index)
2208{
2209 struct hci_dev *hdev;
2210 struct pending_cmd *cmd;
2211 int err;
2212
2213 BT_DBG("hci%u", index);
2214
2215 hdev = hci_dev_get(index);
2216 if (!hdev)
2217 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2218 ENODEV);
2219
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002220 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002221
2222 if (!test_bit(HCI_UP, &hdev->flags)) {
2223 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2224 ENETDOWN);
2225 goto unlock;
2226 }
2227
2228 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2229 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2230 EOPNOTSUPP);
2231 goto unlock;
2232 }
2233
2234 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2235 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2236 goto unlock;
2237 }
2238
2239 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2240 if (!cmd) {
2241 err = -ENOMEM;
2242 goto unlock;
2243 }
2244
2245 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2246 if (err < 0)
2247 mgmt_pending_remove(cmd);
2248
2249unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002250 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002251 hci_dev_put(hdev);
2252
2253 return err;
2254}
2255
Szymon Janc2763eda2011-03-22 13:12:22 +01002256static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2257 u16 len)
2258{
2259 struct hci_dev *hdev;
2260 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2261 int err;
2262
2263 BT_DBG("hci%u ", index);
2264
2265 if (len != sizeof(*cp))
2266 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2267 EINVAL);
2268
2269 hdev = hci_dev_get(index);
2270 if (!hdev)
2271 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2272 ENODEV);
2273
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002274 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002275
2276 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2277 cp->randomizer);
2278 if (err < 0)
2279 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2280 else
2281 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2282 0);
2283
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002284 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285 hci_dev_put(hdev);
2286
2287 return err;
2288}
2289
2290static int remove_remote_oob_data(struct sock *sk, u16 index,
2291 unsigned char *data, u16 len)
2292{
2293 struct hci_dev *hdev;
2294 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2295 int err;
2296
2297 BT_DBG("hci%u ", index);
2298
2299 if (len != sizeof(*cp))
2300 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2301 EINVAL);
2302
2303 hdev = hci_dev_get(index);
2304 if (!hdev)
2305 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2306 ENODEV);
2307
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002308 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002309
2310 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2311 if (err < 0)
2312 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2313 -err);
2314 else
2315 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2316 NULL, 0);
2317
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002318 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002319 hci_dev_put(hdev);
2320
2321 return err;
2322}
2323
Johan Hedberg03811012010-12-08 00:21:06 +02002324int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2325{
2326 unsigned char *buf;
2327 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002328 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002329 int err;
2330
2331 BT_DBG("got %zu bytes", msglen);
2332
2333 if (msglen < sizeof(*hdr))
2334 return -EINVAL;
2335
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002336 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002337 if (!buf)
2338 return -ENOMEM;
2339
2340 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2341 err = -EFAULT;
2342 goto done;
2343 }
2344
2345 hdr = (struct mgmt_hdr *) buf;
2346 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002347 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002348 len = get_unaligned_le16(&hdr->len);
2349
2350 if (len != msglen - sizeof(*hdr)) {
2351 err = -EINVAL;
2352 goto done;
2353 }
2354
Brian Gixa68668b2011-08-11 15:49:36 -07002355 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002356 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002357 case MGMT_OP_READ_VERSION:
2358 err = read_version(sk);
2359 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002360 case MGMT_OP_READ_INDEX_LIST:
2361 err = read_index_list(sk);
2362 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002363 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002364 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002365 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002366 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002367 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002368 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002369 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002370 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002371 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002372 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2373 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2374 len);
2375 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002376 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002377 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002378 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002379 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002380 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002381 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002382 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002383 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002384 break;
2385 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002386 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002387 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002388 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002389 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002390 break;
2391 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002392 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002393 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002394 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002395 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002396 break;
2397 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002398 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002399 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002402 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002403 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002404 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002405 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002406 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002407 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002408 break;
2409 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002410 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002411 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002412 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002413 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002414 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002415 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002416 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002417 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002418 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002419 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002420 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002421 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2422 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002424 case MGMT_OP_SET_LOCAL_NAME:
2425 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2426 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002427 case MGMT_OP_START_DISCOVERY:
2428 err = start_discovery(sk, index);
2429 break;
2430 case MGMT_OP_STOP_DISCOVERY:
2431 err = stop_discovery(sk, index);
2432 break;
2433 case MGMT_OP_RESOLVE_NAME:
2434 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2435 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002436 case MGMT_OP_SET_CONNECTION_PARAMS:
2437 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2438 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002439 case MGMT_OP_SET_RSSI_REPORTER:
2440 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2441 break;
2442 case MGMT_OP_UNSET_RSSI_REPORTER:
2443 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2444 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002445 case MGMT_OP_READ_LOCAL_OOB_DATA:
2446 err = read_local_oob_data(sk, index);
2447 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002448 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2449 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2450 break;
2451 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2452 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2453 len);
2454 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302455 case MGMT_OP_ENCRYPT_LINK:
2456 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2457 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458
Johan Hedberg03811012010-12-08 00:21:06 +02002459 default:
2460 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002461 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002462 break;
2463 }
2464
Johan Hedberge41d8b42010-12-13 21:07:03 +02002465 if (err < 0)
2466 goto done;
2467
Johan Hedberg03811012010-12-08 00:21:06 +02002468 err = msglen;
2469
2470done:
2471 kfree(buf);
2472 return err;
2473}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002474
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002475int mgmt_index_added(u16 index)
2476{
Brian Gixa68668b2011-08-11 15:49:36 -07002477 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002478 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002479}
2480
2481int mgmt_index_removed(u16 index)
2482{
Brian Gixa68668b2011-08-11 15:49:36 -07002483 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002484 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002485}
2486
Johan Hedberg73f22f62010-12-29 16:00:25 +02002487struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002488 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002489 struct sock *sk;
2490};
2491
Johan Hedberg72a734e2010-12-30 00:38:22 +02002492static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002493{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002494 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002495 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002496
Johan Hedberg72a734e2010-12-30 00:38:22 +02002497 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002498 return;
2499
Johan Hedberg053f0212011-01-26 13:07:10 +02002500 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002501
2502 list_del(&cmd->list);
2503
2504 if (match->sk == NULL) {
2505 match->sk = cmd->sk;
2506 sock_hold(match->sk);
2507 }
2508
2509 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002510}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002511
2512int mgmt_powered(u16 index, u8 powered)
2513{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002514 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002515 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002516 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002517
Brian Gixa68668b2011-08-11 15:49:36 -07002518 BT_DBG("hci%u %d", index, powered);
2519
Johan Hedberg72a734e2010-12-30 00:38:22 +02002520 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002521
Johan Hedberg72a734e2010-12-30 00:38:22 +02002522 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002523
Szymon Janc4e51eae2011-02-25 19:05:48 +01002524 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002525
2526 if (match.sk)
2527 sock_put(match.sk);
2528
2529 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002530}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002531
Johan Hedberg73f22f62010-12-29 16:00:25 +02002532int mgmt_discoverable(u16 index, u8 discoverable)
2533{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002534 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002535 struct cmd_lookup match = { discoverable, NULL };
2536 int ret;
2537
Szymon Jancb8534e02011-03-01 16:55:34 +01002538 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002539
Johan Hedberg72a734e2010-12-30 00:38:22 +02002540 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002541
Szymon Janc4e51eae2011-02-25 19:05:48 +01002542 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2543 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002544
2545 if (match.sk)
2546 sock_put(match.sk);
2547
2548 return ret;
2549}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002550
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002551int mgmt_connectable(u16 index, u8 connectable)
2552{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002553 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002554 struct cmd_lookup match = { connectable, NULL };
2555 int ret;
2556
Johan Hedberg72a734e2010-12-30 00:38:22 +02002557 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002558
Johan Hedberg72a734e2010-12-30 00:38:22 +02002559 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002560
Szymon Janc4e51eae2011-02-25 19:05:48 +01002561 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002562
2563 if (match.sk)
2564 sock_put(match.sk);
2565
2566 return ret;
2567}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002568
Brian Gixa68668b2011-08-11 15:49:36 -07002569int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002570{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002571 struct mgmt_ev_new_key *ev;
2572 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002573
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002574 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2575 ev = kzalloc(total, GFP_ATOMIC);
2576 if (!ev)
2577 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002578
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002579 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002580 ev->key.addr_type = key->addr_type;
2581 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002582 memcpy(ev->key.val, key->val, 16);
2583 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002584 ev->key.auth = key->auth;
2585 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002586 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002587
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002588 memcpy(ev->key.data, key->data, key->dlen);
2589
2590 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2591
2592 kfree(ev);
2593
2594 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002595}
Johan Hedbergf7520542011-01-20 12:34:39 +02002596
Brian Gix2e2f50d2011-09-13 12:36:04 -07002597int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002598{
2599 struct mgmt_ev_connected ev;
2600
Johan Hedbergf7520542011-01-20 12:34:39 +02002601 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002602 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002603
Szymon Janc4e51eae2011-02-25 19:05:48 +01002604 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002605}
2606
Johan Hedberg8962ee72011-01-20 12:40:27 +02002607static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2608{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002609 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002610 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002611 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002612
Johan Hedberga38528f2011-01-22 06:46:43 +02002613 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002614
Szymon Janc4e51eae2011-02-25 19:05:48 +01002615 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002616
2617 *sk = cmd->sk;
2618 sock_hold(*sk);
2619
Johan Hedberga664b5b2011-02-19 12:06:02 -03002620 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002621}
2622
Johan Hedbergf7520542011-01-20 12:34:39 +02002623int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2624{
2625 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002626 struct sock *sk = NULL;
2627 int err;
2628
2629 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002630
Johan Hedbergf7520542011-01-20 12:34:39 +02002631 bacpy(&ev.bdaddr, bdaddr);
2632
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002634
2635 if (sk)
2636 sock_put(sk);
2637
2638 return err;
2639}
2640
2641int mgmt_disconnect_failed(u16 index)
2642{
2643 struct pending_cmd *cmd;
2644 int err;
2645
2646 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2647 if (!cmd)
2648 return -ENOENT;
2649
Szymon Janc4e51eae2011-02-25 19:05:48 +01002650 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002651
Johan Hedberga664b5b2011-02-19 12:06:02 -03002652 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002653
2654 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002655}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002656
2657int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2658{
2659 struct mgmt_ev_connect_failed ev;
2660
Johan Hedberg17d5c042011-01-22 06:09:08 +02002661 bacpy(&ev.bdaddr, bdaddr);
2662 ev.status = status;
2663
Szymon Janc4e51eae2011-02-25 19:05:48 +01002664 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002665}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002668{
2669 struct mgmt_ev_pin_code_request ev;
2670
Brian Gixa68668b2011-08-11 15:49:36 -07002671 BT_DBG("hci%u", index);
2672
Johan Hedberg980e1a52011-01-22 06:10:07 +02002673 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002674 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002675
Szymon Janc4e51eae2011-02-25 19:05:48 +01002676 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2677 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002678}
2679
2680int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2681{
2682 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002683 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002684 int err;
2685
2686 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2687 if (!cmd)
2688 return -ENOENT;
2689
Johan Hedbergac56fb12011-02-19 12:05:59 -03002690 bacpy(&rp.bdaddr, bdaddr);
2691 rp.status = status;
2692
Szymon Janc4e51eae2011-02-25 19:05:48 +01002693 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2694 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002695
Johan Hedberga664b5b2011-02-19 12:06:02 -03002696 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002697
2698 return err;
2699}
2700
2701int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2702{
2703 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002704 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002705 int err;
2706
2707 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2708 if (!cmd)
2709 return -ENOENT;
2710
Johan Hedbergac56fb12011-02-19 12:05:59 -03002711 bacpy(&rp.bdaddr, bdaddr);
2712 rp.status = status;
2713
Szymon Janc4e51eae2011-02-25 19:05:48 +01002714 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2715 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002716
Johan Hedberga664b5b2011-02-19 12:06:02 -03002717 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
2719 return err;
2720}
Johan Hedberga5c29682011-02-19 12:05:57 -03002721
Brian Gixa68668b2011-08-11 15:49:36 -07002722int mgmt_user_confirm_request(u16 index, u8 event,
2723 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002724{
2725 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002726 struct hci_conn *conn = NULL;
2727 struct hci_dev *hdev;
2728 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2729
2730 BT_DBG("hci%u", index);
2731
2732 hdev = hci_dev_get(index);
2733
Brian Gix64bd5302011-09-08 11:35:48 -07002734 if (!hdev)
2735 return -ENODEV;
2736
Brian Gix64bd5302011-09-08 11:35:48 -07002737 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002738
2739 ev.auto_confirm = 0;
2740
2741 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2742 goto no_auto_confirm;
2743
2744 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2745 rem_cap = conn->remote_cap;
2746 loc_mitm = conn->auth_type & 0x01;
2747 rem_mitm = conn->remote_auth & 0x01;
2748
Brian Gixdbf59292011-11-11 15:45:17 -08002749 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2750 conn->auth_initiator && rem_cap == 0x03)
2751 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302752 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
2753 if (!loc_mitm && !rem_mitm)
2754 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07002755 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302756 }
Brian Gixa68668b2011-08-11 15:49:36 -07002757
2758
2759 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2760 ev.auto_confirm = 1;
2761
2762no_auto_confirm:
2763 bacpy(&ev.bdaddr, bdaddr);
2764 ev.event = event;
2765 put_unaligned_le32(value, &ev.value);
2766
Brian Gix64bd5302011-09-08 11:35:48 -07002767 hci_dev_put(hdev);
2768
Brian Gixa68668b2011-08-11 15:49:36 -07002769 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2770 NULL);
2771}
2772
2773int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2774{
2775 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002776
2777 BT_DBG("hci%u", index);
2778
Johan Hedberga5c29682011-02-19 12:05:57 -03002779 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002780
Brian Gixa68668b2011-08-11 15:49:36 -07002781 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002782 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002783}
2784
2785static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2786 u8 opcode)
2787{
2788 struct pending_cmd *cmd;
2789 struct mgmt_rp_user_confirm_reply rp;
2790 int err;
2791
2792 cmd = mgmt_pending_find(opcode, index);
2793 if (!cmd)
2794 return -ENOENT;
2795
Johan Hedberga5c29682011-02-19 12:05:57 -03002796 bacpy(&rp.bdaddr, bdaddr);
2797 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002798 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002799
Johan Hedberga664b5b2011-02-19 12:06:02 -03002800 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002801
2802 return err;
2803}
2804
2805int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2806{
2807 return confirm_reply_complete(index, bdaddr, status,
2808 MGMT_OP_USER_CONFIRM_REPLY);
2809}
2810
Szymon Jancb8534e02011-03-01 16:55:34 +01002811int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002812{
2813 return confirm_reply_complete(index, bdaddr, status,
2814 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2815}
Johan Hedberg2a611692011-02-19 12:06:00 -03002816
2817int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2818{
2819 struct mgmt_ev_auth_failed ev;
2820
Johan Hedberg2a611692011-02-19 12:06:00 -03002821 bacpy(&ev.bdaddr, bdaddr);
2822 ev.status = status;
2823
Szymon Janc4e51eae2011-02-25 19:05:48 +01002824 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002825}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002826
2827int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2828{
2829 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002830 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002831 struct mgmt_cp_set_local_name ev;
2832 int err;
2833
2834 memset(&ev, 0, sizeof(ev));
2835 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2836
2837 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2838 if (!cmd)
2839 goto send_event;
2840
2841 if (status) {
2842 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2843 goto failed;
2844 }
2845
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002846 hdev = hci_dev_get(index);
2847 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002848 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002849 hci_dev_put(hdev);
2850 }
2851
Johan Hedbergb312b1612011-03-16 14:29:37 +02002852 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2853 sizeof(ev));
2854 if (err < 0)
2855 goto failed;
2856
2857send_event:
2858 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2859 cmd ? cmd->sk : NULL);
2860
2861failed:
2862 if (cmd)
2863 mgmt_pending_remove(cmd);
2864 return err;
2865}
Szymon Jancc35938b2011-03-22 13:12:21 +01002866
2867int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2868 u8 status)
2869{
2870 struct pending_cmd *cmd;
2871 int err;
2872
2873 BT_DBG("hci%u status %u", index, status);
2874
2875 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2876 if (!cmd)
2877 return -ENOENT;
2878
2879 if (status) {
2880 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2881 EIO);
2882 } else {
2883 struct mgmt_rp_read_local_oob_data rp;
2884
2885 memcpy(rp.hash, hash, sizeof(rp.hash));
2886 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2887
2888 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2889 &rp, sizeof(rp));
2890 }
2891
2892 mgmt_pending_remove(cmd);
2893
2894 return err;
2895}
Johan Hedberge17acd42011-03-30 23:57:16 +03002896
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002897void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
2898 u16 handle, u8 status)
2899{
2900 struct mgmt_ev_rssi_update ev;
2901 struct hci_conn *conn;
2902 struct hci_dev *hdev;
2903
2904 if (status)
2905 return;
2906
2907 hdev = hci_dev_get(index);
2908 conn = hci_conn_hash_lookup_handle(hdev, handle);
2909
2910 if (!conn)
2911 return;
2912
2913 BT_DBG("rssi_update_thresh_exceed : %d ",
2914 conn->rssi_update_thresh_exceed);
2915 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
2916 conn->rssi_threshold, rssi);
2917
2918 if (conn->rssi_update_thresh_exceed == 1) {
2919 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002920 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002921 memset(&ev, 0, sizeof(ev));
2922 bacpy(&ev.bdaddr, bdaddr);
2923 ev.rssi = rssi;
2924 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2925 sizeof(ev), NULL);
2926 } else {
2927 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2928 conn->rssi_update_interval,
2929 conn->rssi_update_thresh_exceed);
2930 }
2931 } else {
2932 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002933 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002934 memset(&ev, 0, sizeof(ev));
2935 bacpy(&ev.bdaddr, bdaddr);
2936 ev.rssi = rssi;
2937 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2938 sizeof(ev), NULL);
2939 } else {
2940 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2941 conn->rssi_update_interval,
2942 conn->rssi_update_thresh_exceed);
2943 }
2944 }
2945}
2946
2947
Brian Gixa68668b2011-08-11 15:49:36 -07002948int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2949 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002950{
2951 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08002952 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07002953 int err;
2954
2955 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002956
2957 memset(&ev, 0, sizeof(ev));
2958
2959 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002960 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002961 ev.type = type;
2962 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002963
Brian Gixa68668b2011-08-11 15:49:36 -07002964 if (dev_class)
2965 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002966
Brian Gixa68668b2011-08-11 15:49:36 -07002967 if (eir && eir_len)
2968 memcpy(ev.eir, eir, eir_len);
2969
2970 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2971
2972 if (err < 0)
2973 return err;
2974
Brian Gix568dde92012-01-11 16:18:04 -08002975 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002976
Brian Gix568dde92012-01-11 16:18:04 -08002977 if (!hdev)
2978 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07002979
Brian Gix568dde92012-01-11 16:18:04 -08002980 if (hdev->disco_state == SCAN_IDLE)
2981 goto done;
2982
2983 hdev->disco_int_count++;
2984
2985 if (hdev->disco_int_count >= hdev->disco_int_phase) {
2986 /* Inquiry scan for General Discovery LAP */
2987 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2988 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2989
2990 hdev->disco_int_phase *= 2;
2991 hdev->disco_int_count = 0;
2992 if (hdev->disco_state == SCAN_LE) {
2993 /* cancel LE scan */
2994 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2995 sizeof(le_cp), &le_cp);
2996 /* start BR scan */
2997 cp.num_rsp = (u8) hdev->disco_int_phase;
2998 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2999 sizeof(cp), &cp);
3000 hdev->disco_state = SCAN_BR;
3001 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003002 }
3003 }
3004
Brian Gix568dde92012-01-11 16:18:04 -08003005done:
3006 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003007 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03003008}
Johan Hedberga88a9652011-03-30 13:18:12 +03003009
Brian Gixa68668b2011-08-11 15:49:36 -07003010
3011int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03003012{
3013 struct mgmt_ev_remote_name ev;
3014
3015 memset(&ev, 0, sizeof(ev));
3016
3017 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003018 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003019 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3020
3021 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
3022}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303023
3024int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
3025{
3026 struct mgmt_ev_encrypt_change ev;
3027
3028 BT_DBG("hci%u", index);
3029
3030 bacpy(&ev.bdaddr, bdaddr);
3031 ev.status = status;
3032
3033 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3034 NULL);
3035}
3036
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303037int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3038{
3039 struct mgmt_ev_remote_class ev;
3040
3041 memset(&ev, 0, sizeof(ev));
3042
3043 bacpy(&ev.bdaddr, bdaddr);
3044 memcpy(ev.dev_class, dev_class, 3);
3045
3046 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3047}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303048
3049int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3050 u16 sub_ver)
3051{
3052 struct mgmt_ev_remote_version ev;
3053
3054 memset(&ev, 0, sizeof(ev));
3055
3056 bacpy(&ev.bdaddr, bdaddr);
3057 ev.lmp_ver = ver;
3058 ev.manufacturer = mnf;
3059 ev.lmp_subver = sub_ver;
3060
3061 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3062}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003063
3064int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3065{
3066 struct mgmt_ev_remote_features ev;
3067
3068 memset(&ev, 0, sizeof(ev));
3069
3070 bacpy(&ev.bdaddr, bdaddr);
3071 memcpy(ev.features, features, sizeof(ev.features));
3072
3073 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3074 NULL);
3075}