blob: 52c1fe6cf3b424f2fc7ea7dadf109cedd624c888 [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 Mc453651c2012-03-02 11:55:59 +05301617 if (io_cap == 0x03) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001618 sec_level = BT_SECURITY_MEDIUM;
1619 auth_type = HCI_AT_DEDICATED_BONDING;
1620 } else {
1621 sec_level = BT_SECURITY_HIGH;
1622 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1623 }
1624
Brian Gixfdd38922011-09-28 16:23:48 -07001625 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1626 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001627 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1628 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001629 } else {
1630 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1631 if (io_cap == 0x04)
1632 io_cap = 0x01;
1633 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1634 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301635 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001636 }
1637
Ville Tervo30e76272011-02-22 16:10:53 -03001638 if (IS_ERR(conn)) {
1639 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001640 goto unlock;
1641 }
1642
1643 if (conn->connect_cfm_cb) {
1644 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001645 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001646 goto unlock;
1647 }
1648
Szymon Janc4e51eae2011-02-25 19:05:48 +01001649 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001650 if (!cmd) {
1651 err = -ENOMEM;
1652 hci_conn_put(conn);
1653 goto unlock;
1654 }
1655
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001656 conn->connect_cfm_cb = pairing_connect_complete_cb;
1657 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001658 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001659 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001660 cmd->user_data = conn;
1661
1662 if (conn->state == BT_CONNECTED &&
1663 hci_conn_security(conn, sec_level, auth_type))
1664 pairing_complete(cmd, 0);
1665
1666 err = 0;
1667
1668unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001669 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001670 hci_dev_put(hdev);
1671
1672 return err;
1673}
1674
Szymon Janc4e51eae2011-02-25 19:05:48 +01001675static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001676 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001677{
1678 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001679 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001680 struct pending_cmd *cmd;
1681 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001682 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001683 int err;
1684
Brian Gixa68668b2011-08-11 15:49:36 -07001685 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001686
Brian Gixa68668b2011-08-11 15:49:36 -07001687 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001688 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001689 else
1690 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001691
Brian Gixa68668b2011-08-11 15:49:36 -07001692 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001693 return cmd_status(sk, index, mgmt_op, EINVAL);
1694
Szymon Janc4e51eae2011-02-25 19:05:48 +01001695 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001696 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001697 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001698
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001699 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001700
Johan Hedberga5c29682011-02-19 12:05:57 -03001701 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001702 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001703 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001704 }
1705
Brian Gixa68668b2011-08-11 15:49:36 -07001706 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1707 if (le_conn) {
1708 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1709 goto done;
1710 }
1711 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1712 "Reject" : "Accept");
1713
Szymon Janc4e51eae2011-02-25 19:05:48 +01001714 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001715 if (!cmd) {
1716 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001717 goto done;
1718 }
1719
1720 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1721 if (err < 0)
1722 mgmt_pending_remove(cmd);
1723
1724done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001725 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001726 hci_dev_put(hdev);
1727
1728 return err;
1729}
1730
1731static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1732 u16 len)
1733{
1734 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1735 struct hci_cp_remote_name_req hci_cp;
1736 struct hci_dev *hdev;
1737 struct pending_cmd *cmd;
1738 int err;
1739
1740 BT_DBG("");
1741
1742 if (len != sizeof(*mgmt_cp))
1743 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1744
1745 hdev = hci_dev_get(index);
1746 if (!hdev)
1747 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1748
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001749 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001750
1751 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1752 if (!cmd) {
1753 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001754 goto failed;
1755 }
1756
Brian Gixa68668b2011-08-11 15:49:36 -07001757 memset(&hci_cp, 0, sizeof(hci_cp));
1758 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1759 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1760 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001761 if (err < 0)
1762 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001763
1764failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001765 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001766 hci_dev_put(hdev);
1767
1768 return err;
1769}
1770
Brian Gix7f7e16c2011-11-01 16:27:25 -07001771static int set_connection_params(struct sock *sk, u16 index,
1772 unsigned char *data, u16 len)
1773{
1774 struct mgmt_cp_set_connection_params *cp = (void *) data;
1775 struct hci_dev *hdev;
1776 struct hci_conn *conn;
1777 int err;
1778
1779 BT_DBG("");
1780
1781 if (len != sizeof(*cp))
1782 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1783 EINVAL);
1784
1785 hdev = hci_dev_get(index);
1786 if (!hdev)
1787 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1788 ENODEV);
1789
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001790 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001791
1792 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1793 if (!conn) {
1794 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1795 ENOTCONN);
1796 goto failed;
1797 }
1798
1799 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1800 le16_to_cpu(cp->interval_max),
1801 le16_to_cpu(cp->slave_latency),
1802 le16_to_cpu(cp->timeout_multiplier));
1803
1804 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1805
1806failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001807 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001808 hci_dev_put(hdev);
1809
1810 return err;
1811}
1812
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001813static int set_rssi_reporter(struct sock *sk, u16 index,
1814 unsigned char *data, u16 len)
1815{
1816 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
1817 struct hci_dev *hdev;
1818 struct hci_conn *conn;
1819 int err = 0;
1820
1821 if (len != sizeof(*cp))
1822 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1823 EINVAL);
1824
1825 hdev = hci_dev_get(index);
1826 if (!hdev)
1827 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1828 ENODEV);
1829
1830 hci_dev_lock(hdev);
1831
1832 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1833
1834 if (!conn) {
1835 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1836 ENOTCONN);
1837 goto failed;
1838 }
1839
1840 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
1841 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
1842 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
1843
1844failed:
1845 hci_dev_unlock(hdev);
1846 hci_dev_put(hdev);
1847
1848 return err;
1849}
1850
1851static int unset_rssi_reporter(struct sock *sk, u16 index,
1852 unsigned char *data, u16 len)
1853{
1854 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
1855 struct hci_dev *hdev;
1856 struct hci_conn *conn;
1857 int err = 0;
1858
1859 if (len != sizeof(*cp))
1860 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1861 EINVAL);
1862
1863 hdev = hci_dev_get(index);
1864
1865 if (!hdev)
1866 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1867 ENODEV);
1868
1869 hci_dev_lock(hdev);
1870
1871 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1872
1873 if (!conn) {
1874 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1875 ENOTCONN);
1876 goto failed;
1877 }
1878
1879 hci_conn_unset_rssi_reporter(conn);
1880
1881failed:
1882 hci_dev_unlock(hdev);
1883 hci_dev_put(hdev);
1884
1885 return err;
1886}
1887
Johan Hedbergb312b1612011-03-16 14:29:37 +02001888static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1889 u16 len)
1890{
1891 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1892 struct hci_cp_write_local_name hci_cp;
1893 struct hci_dev *hdev;
1894 struct pending_cmd *cmd;
1895 int err;
1896
1897 BT_DBG("");
1898
1899 if (len != sizeof(*mgmt_cp))
1900 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1901
1902 hdev = hci_dev_get(index);
1903 if (!hdev)
1904 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1905
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001906 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001907
1908 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1909 if (!cmd) {
1910 err = -ENOMEM;
1911 goto failed;
1912 }
1913
1914 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1915 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1916 &hci_cp);
1917 if (err < 0)
1918 mgmt_pending_remove(cmd);
1919
1920failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001921 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001922 hci_dev_put(hdev);
1923
1924 return err;
1925}
1926
Brian Gixa68668b2011-08-11 15:49:36 -07001927static void discovery_rsp(struct pending_cmd *cmd, void *data)
1928{
1929 struct mgmt_mode ev;
1930
1931 BT_DBG("");
1932 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1933 ev.val = 1;
1934 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1935 } else {
1936 ev.val = 0;
1937 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1938 NULL, 0);
1939 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001940 struct hci_dev *hdev = hci_dev_get(cmd->index);
1941 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08001942 del_timer(&hdev->disco_le_timer);
1943 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001944 hci_dev_put(hdev);
1945 }
Brian Gixa68668b2011-08-11 15:49:36 -07001946 }
1947 }
1948
1949 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1950
1951 list_del(&cmd->list);
1952
1953 mgmt_pending_free(cmd);
1954}
1955
1956void mgmt_inquiry_started(u16 index)
1957{
1958 BT_DBG("");
1959 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1960 discovery_rsp, NULL);
1961}
1962
1963void mgmt_inquiry_complete_evt(u16 index, u8 status)
1964{
1965 struct hci_dev *hdev;
1966 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08001967 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001968 int err = -1;
1969
1970 BT_DBG("");
1971
1972 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001973
Brian Gixa68668b2011-08-11 15:49:36 -07001974 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07001975
1976 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1977 discovery_terminated, NULL);
1978
1979 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001980
Brian Gix64bd5302011-09-08 11:35:48 -07001981 if (hdev)
1982 goto done;
1983 else
1984 return;
1985 }
Brian Gixa68668b2011-08-11 15:49:36 -07001986
Brian Gix568dde92012-01-11 16:18:04 -08001987 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07001988 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1989 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08001990 if (err >= 0) {
1991 mod_timer(&hdev->disco_le_timer, jiffies +
1992 msecs_to_jiffies(hdev->disco_int_phase * 1000));
1993 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07001994 } else
Brian Gix568dde92012-01-11 16:18:04 -08001995 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07001996 }
1997
Brian Gix568dde92012-01-11 16:18:04 -08001998 if (hdev->disco_state == SCAN_IDLE)
1999 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
2000
Brian Gixa68668b2011-08-11 15:49:36 -07002001 if (err < 0)
2002 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2003 discovery_terminated, NULL);
2004
Brian Gix64bd5302011-09-08 11:35:48 -07002005done:
Brian Gixa68668b2011-08-11 15:49:36 -07002006 hci_dev_put(hdev);
2007}
2008
Brian Gix568dde92012-01-11 16:18:04 -08002009void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002010{
Brian Gix568dde92012-01-11 16:18:04 -08002011 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002012 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002013 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002014
Brian Gix568dde92012-01-11 16:18:04 -08002015 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002016
Brian Gix568dde92012-01-11 16:18:04 -08002017 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002018
Brian Gix568dde92012-01-11 16:18:04 -08002019 if (!hdev)
2020 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002021
Brian Gix568dde92012-01-11 16:18:04 -08002022 hci_dev_lock_bh(hdev);
2023 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002024
Brian Gix568dde92012-01-11 16:18:04 -08002025 if (hdev->disco_state != SCAN_IDLE) {
2026 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002027
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302028 if (test_bit(HCI_UP, &hdev->flags)) {
2029 if (hdev->disco_state == SCAN_LE)
2030 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002031 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302032 else
2033 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2034 NULL);
2035 }
Brian Gix568dde92012-01-11 16:18:04 -08002036 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002037 }
Brian Gix568dde92012-01-11 16:18:04 -08002038
2039 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2040
2041 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2042 if (cmd)
2043 mgmt_pending_remove(cmd);
2044
2045 hci_dev_unlock_bh(hdev);
2046 hci_dev_put(hdev);
2047}
2048
2049void mgmt_disco_le_timeout(unsigned long data)
2050{
2051 struct hci_dev *hdev = (void *)data;
2052 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2053
2054 BT_DBG("hci%d", hdev->id);
2055
2056 hdev = hci_dev_get(hdev->id);
2057
2058 if (!hdev)
2059 return;
2060
2061 hci_dev_lock_bh(hdev);
2062
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302063 if (test_bit(HCI_UP, &hdev->flags)) {
2064 if (hdev->disco_state == SCAN_LE)
2065 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2066 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002067
2068 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302069 if (hdev->disco_state != SCAN_IDLE) {
2070 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2071 hdev->disco_int_phase *= 2;
2072 hdev->disco_int_count = 0;
2073 cp.num_rsp = (u8) hdev->disco_int_phase;
2074 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2075 hdev->disco_state = SCAN_BR;
2076 }
Brian Gix568dde92012-01-11 16:18:04 -08002077 }
2078
2079 hci_dev_unlock_bh(hdev);
2080 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002081}
2082
2083static int start_discovery(struct sock *sk, u16 index)
2084{
2085 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2086 struct hci_dev *hdev;
2087 struct pending_cmd *cmd;
2088 int err;
2089
2090 BT_DBG("");
2091
2092 hdev = hci_dev_get(index);
2093 if (!hdev)
2094 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2095
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002096 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002097
Brian Gix568dde92012-01-11 16:18:04 -08002098 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2099 err = -EBUSY;
2100 goto failed;
2101 }
2102
Brian Gixa68668b2011-08-11 15:49:36 -07002103 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2104 if (!cmd) {
2105 err = -ENOMEM;
2106 goto failed;
2107 }
2108
2109 /* If LE Capable, we will alternate between BR/EDR and LE */
2110 if (lmp_le_capable(hdev)) {
2111 struct hci_cp_le_set_scan_parameters le_cp;
2112
2113 /* Shorten BR scan params */
2114 cp.num_rsp = 1;
2115 cp.length /= 2;
2116
2117 /* Setup LE scan params */
2118 memset(&le_cp, 0, sizeof(le_cp));
2119 le_cp.type = 0x01; /* Active scanning */
2120 /* The recommended value for scan interval and window is
2121 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2122 le_cp.interval = cpu_to_le16(0x0012);
2123 le_cp.window = cpu_to_le16(0x0012);
2124 le_cp.own_bdaddr_type = 0; /* Public address */
2125 le_cp.filter = 0; /* Accept all adv packets */
2126
2127 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2128 sizeof(le_cp), &le_cp);
2129 }
2130
2131 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2132
2133 if (err < 0)
2134 mgmt_pending_remove(cmd);
2135 else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002136 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2137 if (!cmd)
2138 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2139 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002140 hdev->disco_int_phase = 1;
2141 hdev->disco_int_count = 0;
2142 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002143 del_timer(&hdev->disco_le_timer);
2144 del_timer(&hdev->disco_timer);
2145 mod_timer(&hdev->disco_timer,
2146 jiffies + msecs_to_jiffies(20000));
Brian Gixa68668b2011-08-11 15:49:36 -07002147 }
2148
2149failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002150 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002151 hci_dev_put(hdev);
2152
Brian Gix568dde92012-01-11 16:18:04 -08002153 if (err < 0)
2154 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2155
Brian Gixa68668b2011-08-11 15:49:36 -07002156 return err;
2157}
2158
2159static int stop_discovery(struct sock *sk, u16 index)
2160{
2161 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2162 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002163 struct hci_dev *hdev;
2164 struct pending_cmd *cmd = NULL;
2165 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002166 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002167
2168 BT_DBG("");
2169
2170 hdev = hci_dev_get(index);
2171 if (!hdev)
2172 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2173
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002174 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002175
Brian Gix568dde92012-01-11 16:18:04 -08002176 state = hdev->disco_state;
2177 hdev->disco_state = SCAN_IDLE;
2178 del_timer(&hdev->disco_le_timer);
2179 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002180
Brian Gix568dde92012-01-11 16:18:04 -08002181 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002182 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2183 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002184 if (err >= 0) {
2185 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2186 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002187
Brian Gix568dde92012-01-11 16:18:04 -08002188 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2189 NULL, 0);
2190 }
Brian Gixa68668b2011-08-11 15:49:36 -07002191 }
2192
Brian Gix568dde92012-01-11 16:18:04 -08002193 if (err < 0)
2194 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002195
Brian Gix568dde92012-01-11 16:18:04 -08002196 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002197 if (err < 0 && cmd)
2198 mgmt_pending_remove(cmd);
2199
2200 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2201
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002202 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002203 hci_dev_put(hdev);
2204
2205 if (err < 0)
2206 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2207 else
2208 return err;
2209}
2210
Szymon Jancc35938b2011-03-22 13:12:21 +01002211static int read_local_oob_data(struct sock *sk, u16 index)
2212{
2213 struct hci_dev *hdev;
2214 struct pending_cmd *cmd;
2215 int err;
2216
2217 BT_DBG("hci%u", index);
2218
2219 hdev = hci_dev_get(index);
2220 if (!hdev)
2221 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2222 ENODEV);
2223
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002224 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002225
2226 if (!test_bit(HCI_UP, &hdev->flags)) {
2227 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2228 ENETDOWN);
2229 goto unlock;
2230 }
2231
2232 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2233 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2234 EOPNOTSUPP);
2235 goto unlock;
2236 }
2237
2238 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2239 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2240 goto unlock;
2241 }
2242
2243 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2244 if (!cmd) {
2245 err = -ENOMEM;
2246 goto unlock;
2247 }
2248
2249 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2250 if (err < 0)
2251 mgmt_pending_remove(cmd);
2252
2253unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002254 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002255 hci_dev_put(hdev);
2256
2257 return err;
2258}
2259
Szymon Janc2763eda2011-03-22 13:12:22 +01002260static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2261 u16 len)
2262{
2263 struct hci_dev *hdev;
2264 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2265 int err;
2266
2267 BT_DBG("hci%u ", index);
2268
2269 if (len != sizeof(*cp))
2270 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2271 EINVAL);
2272
2273 hdev = hci_dev_get(index);
2274 if (!hdev)
2275 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2276 ENODEV);
2277
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002278 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002279
2280 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2281 cp->randomizer);
2282 if (err < 0)
2283 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2284 else
2285 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2286 0);
2287
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002288 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002289 hci_dev_put(hdev);
2290
2291 return err;
2292}
2293
2294static int remove_remote_oob_data(struct sock *sk, u16 index,
2295 unsigned char *data, u16 len)
2296{
2297 struct hci_dev *hdev;
2298 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2299 int err;
2300
2301 BT_DBG("hci%u ", index);
2302
2303 if (len != sizeof(*cp))
2304 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2305 EINVAL);
2306
2307 hdev = hci_dev_get(index);
2308 if (!hdev)
2309 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2310 ENODEV);
2311
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002312 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002313
2314 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2315 if (err < 0)
2316 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2317 -err);
2318 else
2319 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2320 NULL, 0);
2321
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002322 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002323 hci_dev_put(hdev);
2324
2325 return err;
2326}
2327
Johan Hedberg03811012010-12-08 00:21:06 +02002328int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2329{
2330 unsigned char *buf;
2331 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002332 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002333 int err;
2334
2335 BT_DBG("got %zu bytes", msglen);
2336
2337 if (msglen < sizeof(*hdr))
2338 return -EINVAL;
2339
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002340 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002341 if (!buf)
2342 return -ENOMEM;
2343
2344 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2345 err = -EFAULT;
2346 goto done;
2347 }
2348
2349 hdr = (struct mgmt_hdr *) buf;
2350 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002351 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002352 len = get_unaligned_le16(&hdr->len);
2353
2354 if (len != msglen - sizeof(*hdr)) {
2355 err = -EINVAL;
2356 goto done;
2357 }
2358
Brian Gixa68668b2011-08-11 15:49:36 -07002359 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002360 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002361 case MGMT_OP_READ_VERSION:
2362 err = read_version(sk);
2363 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002364 case MGMT_OP_READ_INDEX_LIST:
2365 err = read_index_list(sk);
2366 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002367 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002368 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002369 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002370 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002371 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002372 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002373 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002374 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002375 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002376 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2377 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2378 len);
2379 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002380 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002381 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002382 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002383 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002384 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002385 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002386 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002387 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002388 break;
2389 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002390 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002391 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002392 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002393 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002394 break;
2395 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002396 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002397 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002398 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002399 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002400 break;
2401 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002402 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002403 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002404 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002405 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002406 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002407 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002408 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002409 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002410 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002411 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002412 break;
2413 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002414 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002415 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002416 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002417 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002418 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002419 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002420 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002421 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002422 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002423 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002424 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002425 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2426 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002427 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002428 case MGMT_OP_SET_LOCAL_NAME:
2429 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2430 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002431 case MGMT_OP_START_DISCOVERY:
2432 err = start_discovery(sk, index);
2433 break;
2434 case MGMT_OP_STOP_DISCOVERY:
2435 err = stop_discovery(sk, index);
2436 break;
2437 case MGMT_OP_RESOLVE_NAME:
2438 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2439 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002440 case MGMT_OP_SET_CONNECTION_PARAMS:
2441 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2442 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002443 case MGMT_OP_SET_RSSI_REPORTER:
2444 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2445 break;
2446 case MGMT_OP_UNSET_RSSI_REPORTER:
2447 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2448 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002449 case MGMT_OP_READ_LOCAL_OOB_DATA:
2450 err = read_local_oob_data(sk, index);
2451 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002452 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2453 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2454 break;
2455 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2456 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2457 len);
2458 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302459 case MGMT_OP_ENCRYPT_LINK:
2460 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2461 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462
Johan Hedberg03811012010-12-08 00:21:06 +02002463 default:
2464 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002465 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002466 break;
2467 }
2468
Johan Hedberge41d8b42010-12-13 21:07:03 +02002469 if (err < 0)
2470 goto done;
2471
Johan Hedberg03811012010-12-08 00:21:06 +02002472 err = msglen;
2473
2474done:
2475 kfree(buf);
2476 return err;
2477}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002478
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002479int mgmt_index_added(u16 index)
2480{
Brian Gixa68668b2011-08-11 15:49:36 -07002481 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002482 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002483}
2484
2485int mgmt_index_removed(u16 index)
2486{
Brian Gixa68668b2011-08-11 15:49:36 -07002487 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002488 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002489}
2490
Johan Hedberg73f22f62010-12-29 16:00:25 +02002491struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002492 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002493 struct sock *sk;
2494};
2495
Johan Hedberg72a734e2010-12-30 00:38:22 +02002496static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002497{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002498 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002499 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002500
Johan Hedberg72a734e2010-12-30 00:38:22 +02002501 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002502 return;
2503
Johan Hedberg053f0212011-01-26 13:07:10 +02002504 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002505
2506 list_del(&cmd->list);
2507
2508 if (match->sk == NULL) {
2509 match->sk = cmd->sk;
2510 sock_hold(match->sk);
2511 }
2512
2513 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002514}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002515
2516int mgmt_powered(u16 index, u8 powered)
2517{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002518 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002519 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002520 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002521
Brian Gixa68668b2011-08-11 15:49:36 -07002522 BT_DBG("hci%u %d", index, powered);
2523
Johan Hedberg72a734e2010-12-30 00:38:22 +02002524 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002525
Johan Hedberg72a734e2010-12-30 00:38:22 +02002526 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002527
Szymon Janc4e51eae2011-02-25 19:05:48 +01002528 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002529
2530 if (match.sk)
2531 sock_put(match.sk);
2532
2533 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002534}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002535
Johan Hedberg73f22f62010-12-29 16:00:25 +02002536int mgmt_discoverable(u16 index, u8 discoverable)
2537{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002538 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002539 struct cmd_lookup match = { discoverable, NULL };
2540 int ret;
2541
Szymon Jancb8534e02011-03-01 16:55:34 +01002542 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002543
Johan Hedberg72a734e2010-12-30 00:38:22 +02002544 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002545
Szymon Janc4e51eae2011-02-25 19:05:48 +01002546 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2547 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002548
2549 if (match.sk)
2550 sock_put(match.sk);
2551
2552 return ret;
2553}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002554
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002555int mgmt_connectable(u16 index, u8 connectable)
2556{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002557 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002558 struct cmd_lookup match = { connectable, NULL };
2559 int ret;
2560
Johan Hedberg72a734e2010-12-30 00:38:22 +02002561 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002562
Johan Hedberg72a734e2010-12-30 00:38:22 +02002563 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002564
Szymon Janc4e51eae2011-02-25 19:05:48 +01002565 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002566
2567 if (match.sk)
2568 sock_put(match.sk);
2569
2570 return ret;
2571}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002572
Brian Gixa68668b2011-08-11 15:49:36 -07002573int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002574{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002575 struct mgmt_ev_new_key *ev;
2576 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002577
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002578 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2579 ev = kzalloc(total, GFP_ATOMIC);
2580 if (!ev)
2581 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002582
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002583 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002584 ev->key.addr_type = key->addr_type;
2585 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002586 memcpy(ev->key.val, key->val, 16);
2587 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002588 ev->key.auth = key->auth;
2589 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002590 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002591
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002592 memcpy(ev->key.data, key->data, key->dlen);
2593
2594 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2595
2596 kfree(ev);
2597
2598 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002599}
Johan Hedbergf7520542011-01-20 12:34:39 +02002600
Brian Gix2e2f50d2011-09-13 12:36:04 -07002601int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002602{
2603 struct mgmt_ev_connected ev;
2604
Johan Hedbergf7520542011-01-20 12:34:39 +02002605 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002606 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002607
Szymon Janc4e51eae2011-02-25 19:05:48 +01002608 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002609}
2610
Johan Hedberg8962ee72011-01-20 12:40:27 +02002611static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2612{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002613 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002614 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002615 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002616
Johan Hedberga38528f2011-01-22 06:46:43 +02002617 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002618
Szymon Janc4e51eae2011-02-25 19:05:48 +01002619 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002620
2621 *sk = cmd->sk;
2622 sock_hold(*sk);
2623
Johan Hedberga664b5b2011-02-19 12:06:02 -03002624 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002625}
2626
Johan Hedbergf7520542011-01-20 12:34:39 +02002627int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2628{
2629 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002630 struct sock *sk = NULL;
2631 int err;
2632
2633 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002634
Johan Hedbergf7520542011-01-20 12:34:39 +02002635 bacpy(&ev.bdaddr, bdaddr);
2636
Szymon Janc4e51eae2011-02-25 19:05:48 +01002637 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002638
2639 if (sk)
2640 sock_put(sk);
2641
2642 return err;
2643}
2644
2645int mgmt_disconnect_failed(u16 index)
2646{
2647 struct pending_cmd *cmd;
2648 int err;
2649
2650 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2651 if (!cmd)
2652 return -ENOENT;
2653
Szymon Janc4e51eae2011-02-25 19:05:48 +01002654 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002655
Johan Hedberga664b5b2011-02-19 12:06:02 -03002656 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002657
2658 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002659}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002660
2661int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2662{
2663 struct mgmt_ev_connect_failed ev;
2664
Johan Hedberg17d5c042011-01-22 06:09:08 +02002665 bacpy(&ev.bdaddr, bdaddr);
2666 ev.status = status;
2667
Szymon Janc4e51eae2011-02-25 19:05:48 +01002668 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002669}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002672{
2673 struct mgmt_ev_pin_code_request ev;
2674
Brian Gixa68668b2011-08-11 15:49:36 -07002675 BT_DBG("hci%u", index);
2676
Johan Hedberg980e1a52011-01-22 06:10:07 +02002677 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002678 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002679
Szymon Janc4e51eae2011-02-25 19:05:48 +01002680 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2681 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002682}
2683
2684int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2685{
2686 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002687 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002688 int err;
2689
2690 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2691 if (!cmd)
2692 return -ENOENT;
2693
Johan Hedbergac56fb12011-02-19 12:05:59 -03002694 bacpy(&rp.bdaddr, bdaddr);
2695 rp.status = status;
2696
Szymon Janc4e51eae2011-02-25 19:05:48 +01002697 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2698 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002699
Johan Hedberga664b5b2011-02-19 12:06:02 -03002700 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701
2702 return err;
2703}
2704
2705int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2706{
2707 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002708 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709 int err;
2710
2711 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2712 if (!cmd)
2713 return -ENOENT;
2714
Johan Hedbergac56fb12011-02-19 12:05:59 -03002715 bacpy(&rp.bdaddr, bdaddr);
2716 rp.status = status;
2717
Szymon Janc4e51eae2011-02-25 19:05:48 +01002718 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2719 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720
Johan Hedberga664b5b2011-02-19 12:06:02 -03002721 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722
2723 return err;
2724}
Johan Hedberga5c29682011-02-19 12:05:57 -03002725
Brian Gixa68668b2011-08-11 15:49:36 -07002726int mgmt_user_confirm_request(u16 index, u8 event,
2727 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002728{
2729 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002730 struct hci_conn *conn = NULL;
2731 struct hci_dev *hdev;
2732 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2733
2734 BT_DBG("hci%u", index);
2735
2736 hdev = hci_dev_get(index);
2737
Brian Gix64bd5302011-09-08 11:35:48 -07002738 if (!hdev)
2739 return -ENODEV;
2740
Brian Gix64bd5302011-09-08 11:35:48 -07002741 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002742
2743 ev.auto_confirm = 0;
2744
2745 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2746 goto no_auto_confirm;
2747
2748 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2749 rem_cap = conn->remote_cap;
2750 loc_mitm = conn->auth_type & 0x01;
2751 rem_mitm = conn->remote_auth & 0x01;
2752
Brian Gixdbf59292011-11-11 15:45:17 -08002753 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2754 conn->auth_initiator && rem_cap == 0x03)
2755 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302756 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
2757 if (!loc_mitm && !rem_mitm)
2758 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07002759 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302760 }
Brian Gixa68668b2011-08-11 15:49:36 -07002761
2762
2763 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2764 ev.auto_confirm = 1;
2765
2766no_auto_confirm:
2767 bacpy(&ev.bdaddr, bdaddr);
2768 ev.event = event;
2769 put_unaligned_le32(value, &ev.value);
2770
Brian Gix64bd5302011-09-08 11:35:48 -07002771 hci_dev_put(hdev);
2772
Brian Gixa68668b2011-08-11 15:49:36 -07002773 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2774 NULL);
2775}
2776
2777int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2778{
2779 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002780
2781 BT_DBG("hci%u", index);
2782
Johan Hedberga5c29682011-02-19 12:05:57 -03002783 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002784
Brian Gixa68668b2011-08-11 15:49:36 -07002785 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002786 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002787}
2788
2789static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2790 u8 opcode)
2791{
2792 struct pending_cmd *cmd;
2793 struct mgmt_rp_user_confirm_reply rp;
2794 int err;
2795
2796 cmd = mgmt_pending_find(opcode, index);
2797 if (!cmd)
2798 return -ENOENT;
2799
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 bacpy(&rp.bdaddr, bdaddr);
2801 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002802 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002803
Johan Hedberga664b5b2011-02-19 12:06:02 -03002804 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002805
2806 return err;
2807}
2808
2809int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2810{
2811 return confirm_reply_complete(index, bdaddr, status,
2812 MGMT_OP_USER_CONFIRM_REPLY);
2813}
2814
Szymon Jancb8534e02011-03-01 16:55:34 +01002815int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002816{
2817 return confirm_reply_complete(index, bdaddr, status,
2818 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2819}
Johan Hedberg2a611692011-02-19 12:06:00 -03002820
2821int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2822{
2823 struct mgmt_ev_auth_failed ev;
2824
Johan Hedberg2a611692011-02-19 12:06:00 -03002825 bacpy(&ev.bdaddr, bdaddr);
2826 ev.status = status;
2827
Szymon Janc4e51eae2011-02-25 19:05:48 +01002828 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002829}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002830
2831int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2832{
2833 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002834 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002835 struct mgmt_cp_set_local_name ev;
2836 int err;
2837
2838 memset(&ev, 0, sizeof(ev));
2839 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2840
2841 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2842 if (!cmd)
2843 goto send_event;
2844
2845 if (status) {
2846 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2847 goto failed;
2848 }
2849
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002850 hdev = hci_dev_get(index);
2851 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002852 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002853 hci_dev_put(hdev);
2854 }
2855
Johan Hedbergb312b1612011-03-16 14:29:37 +02002856 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2857 sizeof(ev));
2858 if (err < 0)
2859 goto failed;
2860
2861send_event:
2862 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2863 cmd ? cmd->sk : NULL);
2864
2865failed:
2866 if (cmd)
2867 mgmt_pending_remove(cmd);
2868 return err;
2869}
Szymon Jancc35938b2011-03-22 13:12:21 +01002870
2871int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2872 u8 status)
2873{
2874 struct pending_cmd *cmd;
2875 int err;
2876
2877 BT_DBG("hci%u status %u", index, status);
2878
2879 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2880 if (!cmd)
2881 return -ENOENT;
2882
2883 if (status) {
2884 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2885 EIO);
2886 } else {
2887 struct mgmt_rp_read_local_oob_data rp;
2888
2889 memcpy(rp.hash, hash, sizeof(rp.hash));
2890 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2891
2892 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2893 &rp, sizeof(rp));
2894 }
2895
2896 mgmt_pending_remove(cmd);
2897
2898 return err;
2899}
Johan Hedberge17acd42011-03-30 23:57:16 +03002900
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002901void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
2902 u16 handle, u8 status)
2903{
2904 struct mgmt_ev_rssi_update ev;
2905 struct hci_conn *conn;
2906 struct hci_dev *hdev;
2907
2908 if (status)
2909 return;
2910
2911 hdev = hci_dev_get(index);
2912 conn = hci_conn_hash_lookup_handle(hdev, handle);
2913
2914 if (!conn)
2915 return;
2916
2917 BT_DBG("rssi_update_thresh_exceed : %d ",
2918 conn->rssi_update_thresh_exceed);
2919 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
2920 conn->rssi_threshold, rssi);
2921
2922 if (conn->rssi_update_thresh_exceed == 1) {
2923 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002924 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002925 memset(&ev, 0, sizeof(ev));
2926 bacpy(&ev.bdaddr, bdaddr);
2927 ev.rssi = rssi;
2928 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2929 sizeof(ev), NULL);
2930 } else {
2931 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2932 conn->rssi_update_interval,
2933 conn->rssi_update_thresh_exceed);
2934 }
2935 } else {
2936 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002937 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002938 memset(&ev, 0, sizeof(ev));
2939 bacpy(&ev.bdaddr, bdaddr);
2940 ev.rssi = rssi;
2941 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2942 sizeof(ev), NULL);
2943 } else {
2944 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2945 conn->rssi_update_interval,
2946 conn->rssi_update_thresh_exceed);
2947 }
2948 }
2949}
2950
2951
Brian Gixa68668b2011-08-11 15:49:36 -07002952int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2953 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002954{
2955 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08002956 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07002957 int err;
2958
2959 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002960
2961 memset(&ev, 0, sizeof(ev));
2962
2963 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002964 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002965 ev.type = type;
2966 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002967
Brian Gixa68668b2011-08-11 15:49:36 -07002968 if (dev_class)
2969 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002970
Brian Gixa68668b2011-08-11 15:49:36 -07002971 if (eir && eir_len)
2972 memcpy(ev.eir, eir, eir_len);
2973
2974 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2975
2976 if (err < 0)
2977 return err;
2978
Brian Gix568dde92012-01-11 16:18:04 -08002979 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002980
Brian Gix568dde92012-01-11 16:18:04 -08002981 if (!hdev)
2982 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07002983
Brian Gix568dde92012-01-11 16:18:04 -08002984 if (hdev->disco_state == SCAN_IDLE)
2985 goto done;
2986
2987 hdev->disco_int_count++;
2988
2989 if (hdev->disco_int_count >= hdev->disco_int_phase) {
2990 /* Inquiry scan for General Discovery LAP */
2991 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2992 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2993
2994 hdev->disco_int_phase *= 2;
2995 hdev->disco_int_count = 0;
2996 if (hdev->disco_state == SCAN_LE) {
2997 /* cancel LE scan */
2998 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2999 sizeof(le_cp), &le_cp);
3000 /* start BR scan */
3001 cp.num_rsp = (u8) hdev->disco_int_phase;
3002 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3003 sizeof(cp), &cp);
3004 hdev->disco_state = SCAN_BR;
3005 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003006 }
3007 }
3008
Brian Gix568dde92012-01-11 16:18:04 -08003009done:
3010 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003011 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03003012}
Johan Hedberga88a9652011-03-30 13:18:12 +03003013
Brian Gixa68668b2011-08-11 15:49:36 -07003014
3015int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03003016{
3017 struct mgmt_ev_remote_name ev;
3018
3019 memset(&ev, 0, sizeof(ev));
3020
3021 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003022 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003023 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3024
3025 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
3026}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303027
3028int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
3029{
3030 struct mgmt_ev_encrypt_change ev;
3031
3032 BT_DBG("hci%u", index);
3033
3034 bacpy(&ev.bdaddr, bdaddr);
3035 ev.status = status;
3036
3037 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3038 NULL);
3039}
3040
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303041int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3042{
3043 struct mgmt_ev_remote_class ev;
3044
3045 memset(&ev, 0, sizeof(ev));
3046
3047 bacpy(&ev.bdaddr, bdaddr);
3048 memcpy(ev.dev_class, dev_class, 3);
3049
3050 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3051}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303052
3053int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3054 u16 sub_ver)
3055{
3056 struct mgmt_ev_remote_version ev;
3057
3058 memset(&ev, 0, sizeof(ev));
3059
3060 bacpy(&ev.bdaddr, bdaddr);
3061 ev.lmp_ver = ver;
3062 ev.manufacturer = mnf;
3063 ev.lmp_subver = sub_ver;
3064
3065 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3066}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003067
3068int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3069{
3070 struct mgmt_ev_remote_features ev;
3071
3072 memset(&ev, 0, sizeof(ev));
3073
3074 bacpy(&ev.bdaddr, bdaddr);
3075 memcpy(ev.features, features, sizeof(ev.features));
3076
3077 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3078 NULL);
3079}