blob: 86ae7637fd458ea5187731ed6a8efdd1b2c9972f [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
Johan Hedberg931bc4e2011-11-03 14:40:33 +0200311 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312 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 Jancb8534e0f2011-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
Brian Gix384ec672012-03-08 18:41:15 -08001356 hci_dev_lock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301357
1358 if (!test_bit(HCI_UP, &hdev->flags)) {
1359 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
Brian Gix384ec672012-03-08 18:41:15 -08001360 goto done;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301361 }
1362
Brian Gix384ec672012-03-08 18:41:15 -08001363 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1364 if (!conn) {
1365 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1366 goto done;
1367 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301368
Brian Gix384ec672012-03-08 18:41:15 -08001369 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
1370 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1371 goto done;
1372 }
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301373
1374 if (conn->link_mode & HCI_LM_AUTH) {
1375 enc.handle = cpu_to_le16(conn->handle);
1376 enc.encrypt = cp->enable;
1377 err = hci_send_cmd(hdev,
1378 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1379 } else {
1380 conn->auth_initiator = 1;
1381 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1382 struct hci_cp_auth_requested cp;
1383 cp.handle = cpu_to_le16(conn->handle);
1384 err = hci_send_cmd(conn->hdev,
1385 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1386 }
1387 }
1388
Brian Gix384ec672012-03-08 18:41:15 -08001389done:
1390 hci_dev_unlock_bh(hdev);
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301391 hci_dev_put(hdev);
1392
1393 return err;
1394}
1395
1396
Szymon Janc4e51eae2011-02-25 19:05:48 +01001397static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1398 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001399{
1400 struct hci_dev *hdev;
1401 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001403 int err;
1404
1405 BT_DBG("");
1406
1407 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001408
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001409 if (len != sizeof(*cp))
1410 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1411 EINVAL);
1412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001414 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1416 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001418 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419
1420 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001421 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1422 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423 goto failed;
1424 }
1425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1427 data, len);
1428 if (!cmd) {
1429 err = -ENOMEM;
1430 goto failed;
1431 }
1432
1433 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1434 &cp->bdaddr);
1435 if (err < 0)
1436 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001437
1438failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001439 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001440 hci_dev_put(hdev);
1441
1442 return err;
1443}
1444
Szymon Janc4e51eae2011-02-25 19:05:48 +01001445static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1446 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001447{
1448 struct hci_dev *hdev;
1449 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001450
1451 BT_DBG("");
1452
1453 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001454
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001455 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001456 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001457
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001459 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001460 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001461
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001462 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001463
1464 hdev->io_capability = cp->io_capability;
1465
1466 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001467 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001468
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001469 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001470 hci_dev_put(hdev);
1471
Szymon Janc4e51eae2011-02-25 19:05:48 +01001472 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001473}
1474
Johan Hedberge9a416b2011-02-19 12:05:56 -03001475static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1476{
1477 struct hci_dev *hdev = conn->hdev;
1478 struct list_head *p;
1479
1480 list_for_each(p, &cmd_list) {
1481 struct pending_cmd *cmd;
1482
1483 cmd = list_entry(p, struct pending_cmd, list);
1484
1485 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1486 continue;
1487
1488 if (cmd->index != hdev->id)
1489 continue;
1490
1491 if (cmd->user_data != conn)
1492 continue;
1493
1494 return cmd;
1495 }
1496
1497 return NULL;
1498}
1499
1500static void pairing_complete(struct pending_cmd *cmd, u8 status)
1501{
1502 struct mgmt_rp_pair_device rp;
1503 struct hci_conn *conn = cmd->user_data;
1504
Brian Gixa68668b2011-08-11 15:49:36 -07001505 BT_DBG(" %u", status);
1506
Johan Hedberge9a416b2011-02-19 12:05:56 -03001507 bacpy(&rp.bdaddr, &conn->dst);
1508 rp.status = status;
1509
Szymon Janc4e51eae2011-02-25 19:05:48 +01001510 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511
1512 /* So we don't get further callbacks for this connection */
1513 conn->connect_cfm_cb = NULL;
1514 conn->security_cfm_cb = NULL;
1515 conn->disconn_cfm_cb = NULL;
1516
Johan Hedberga664b5b2011-02-19 12:06:02 -03001517 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001518}
1519
1520static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1521{
1522 struct pending_cmd *cmd;
1523
Brian Gixa68668b2011-08-11 15:49:36 -07001524 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001525
1526 cmd = find_pairing(conn);
1527 if (!cmd) {
1528 BT_DBG("Unable to find a pending command");
1529 return;
1530 }
1531
1532 pairing_complete(cmd, status);
Brian Gix80fb3a92012-01-31 13:15:20 -08001533 hci_conn_put(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001534}
1535
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001536static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001537{
1538 struct pending_cmd *cmd;
1539
1540 BT_DBG(" %u", status);
1541
1542 cmd = find_pairing(conn);
1543 if (!cmd) {
1544 BT_DBG("Unable to find a pending command");
1545 return;
1546 }
1547
1548 if (conn->type == LE_LINK)
1549 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1550 status ? 0 : 1);
1551 else
1552 pairing_complete(cmd, status);
1553}
1554
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001555static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001556{
1557 struct pending_cmd *cmd;
1558
1559 BT_DBG("conn: %p %u", conn, status);
1560
1561 cmd = find_pairing(conn);
1562 if (!cmd) {
1563 BT_DBG("Unable to find a pending command");
1564 return;
1565 }
Brian Gix114f3a62011-09-27 14:02:20 -07001566
1567 if (status)
1568 pairing_complete(cmd, status);
1569
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001570 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001571}
1572
1573static void discovery_terminated(struct pending_cmd *cmd, void *data)
1574{
Brian Gix6e349d02011-11-28 14:51:14 -08001575 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001576 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001577
1578 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001579 hdev = hci_dev_get(cmd->index);
1580 if (!hdev)
1581 goto not_found;
1582
Brian Gix568dde92012-01-11 16:18:04 -08001583 del_timer(&hdev->disco_le_timer);
1584 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001585 hci_dev_put(hdev);
1586
1587not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001588 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1589
1590 list_del(&cmd->list);
1591
1592 mgmt_pending_free(cmd);
1593}
1594
Szymon Janc4e51eae2011-02-25 19:05:48 +01001595static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001596{
1597 struct hci_dev *hdev;
1598 struct mgmt_cp_pair_device *cp;
1599 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001600 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001601 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001602 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001603 int err;
1604
1605 BT_DBG("");
1606
Brian Gix64bd5302011-09-08 11:35:48 -07001607 cp = (void *) data;
1608
1609 if (len != sizeof(*cp))
1610 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1611
Szymon Janc4e51eae2011-02-25 19:05:48 +01001612 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001613
Johan Hedberge9a416b2011-02-19 12:05:56 -03001614 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001615 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001616
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001617 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001618
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301619 io_cap = cp->io_cap;
Prabhakaran Mc76a83552012-04-09 14:43:18 +05301620
1621 sec_level = BT_SECURITY_MEDIUM;
1622 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001623
Brian Gixfdd38922011-09-28 16:23:48 -07001624 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1625 if (entry && entry->flags & 0x04) {
Brian Gixa94b6122012-02-23 16:07:10 -08001626 conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
1627 auth_type, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001628 } else {
1629 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1630 if (io_cap == 0x04)
1631 io_cap = 0x01;
1632 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1633 auth_type);
Prabhakaran Mc453651c2012-03-02 11:55:59 +05301634 conn->auth_initiator = 1;
Brian Gixa68668b2011-08-11 15:49:36 -07001635 }
1636
Ville Tervo30e76272011-02-22 16:10:53 -03001637 if (IS_ERR(conn)) {
1638 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001639 goto unlock;
1640 }
1641
1642 if (conn->connect_cfm_cb) {
1643 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001645 goto unlock;
1646 }
1647
Szymon Janc4e51eae2011-02-25 19:05:48 +01001648 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001649 if (!cmd) {
1650 err = -ENOMEM;
1651 hci_conn_put(conn);
1652 goto unlock;
1653 }
1654
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001655 conn->connect_cfm_cb = pairing_connect_complete_cb;
1656 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001657 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001658 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001659 cmd->user_data = conn;
1660
1661 if (conn->state == BT_CONNECTED &&
1662 hci_conn_security(conn, sec_level, auth_type))
1663 pairing_complete(cmd, 0);
1664
1665 err = 0;
1666
1667unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001668 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001669 hci_dev_put(hdev);
1670
1671 return err;
1672}
1673
Szymon Janc4e51eae2011-02-25 19:05:48 +01001674static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001675 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001676{
1677 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001678 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 struct pending_cmd *cmd;
1680 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001681 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001682 int err;
1683
Brian Gixa68668b2011-08-11 15:49:36 -07001684 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001685
Brian Gixa68668b2011-08-11 15:49:36 -07001686 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001687 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001688 else
1689 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001690
Brian Gixa68668b2011-08-11 15:49:36 -07001691 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001692 return cmd_status(sk, index, mgmt_op, EINVAL);
1693
Szymon Janc4e51eae2011-02-25 19:05:48 +01001694 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001695 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001696 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001697
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001698 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001699
Johan Hedberga5c29682011-02-19 12:05:57 -03001700 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001701 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001702 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001703 }
1704
Brian Gixa68668b2011-08-11 15:49:36 -07001705 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1706 if (le_conn) {
1707 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1708 goto done;
1709 }
1710 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1711 "Reject" : "Accept");
1712
Szymon Janc4e51eae2011-02-25 19:05:48 +01001713 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001714 if (!cmd) {
1715 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001716 goto done;
1717 }
1718
1719 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1720 if (err < 0)
1721 mgmt_pending_remove(cmd);
1722
1723done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001724 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001725 hci_dev_put(hdev);
1726
1727 return err;
1728}
1729
1730static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1731 u16 len)
1732{
1733 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1734 struct hci_cp_remote_name_req hci_cp;
1735 struct hci_dev *hdev;
1736 struct pending_cmd *cmd;
1737 int err;
1738
1739 BT_DBG("");
1740
1741 if (len != sizeof(*mgmt_cp))
1742 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1743
1744 hdev = hci_dev_get(index);
1745 if (!hdev)
1746 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1747
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001748 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001749
1750 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1751 if (!cmd) {
1752 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001753 goto failed;
1754 }
1755
Brian Gixa68668b2011-08-11 15:49:36 -07001756 memset(&hci_cp, 0, sizeof(hci_cp));
1757 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1758 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1759 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001760 if (err < 0)
1761 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001762
1763failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001764 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001765 hci_dev_put(hdev);
1766
1767 return err;
1768}
1769
Brian Gix7f7e16c2011-11-01 16:27:25 -07001770static int set_connection_params(struct sock *sk, u16 index,
1771 unsigned char *data, u16 len)
1772{
1773 struct mgmt_cp_set_connection_params *cp = (void *) data;
1774 struct hci_dev *hdev;
1775 struct hci_conn *conn;
1776 int err;
1777
1778 BT_DBG("");
1779
1780 if (len != sizeof(*cp))
1781 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1782 EINVAL);
1783
1784 hdev = hci_dev_get(index);
1785 if (!hdev)
1786 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1787 ENODEV);
1788
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001789 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001790
1791 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1792 if (!conn) {
1793 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1794 ENOTCONN);
1795 goto failed;
1796 }
1797
1798 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1799 le16_to_cpu(cp->interval_max),
1800 le16_to_cpu(cp->slave_latency),
1801 le16_to_cpu(cp->timeout_multiplier));
1802
1803 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1804
1805failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001806 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001812static int set_rssi_reporter(struct sock *sk, u16 index,
1813 unsigned char *data, u16 len)
1814{
1815 struct mgmt_cp_set_rssi_reporter *cp = (void *) data;
1816 struct hci_dev *hdev;
1817 struct hci_conn *conn;
1818 int err = 0;
1819
1820 if (len != sizeof(*cp))
1821 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1822 EINVAL);
1823
1824 hdev = hci_dev_get(index);
1825 if (!hdev)
1826 return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1827 ENODEV);
1828
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001829 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001830
1831 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1832
1833 if (!conn) {
1834 err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER,
1835 ENOTCONN);
1836 goto failed;
1837 }
1838
1839 BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed);
1840 hci_conn_set_rssi_reporter(conn, cp->rssi_threshold,
1841 __le16_to_cpu(cp->interval), cp->updateOnThreshExceed);
1842
1843failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001844 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001845 hci_dev_put(hdev);
1846
1847 return err;
1848}
1849
1850static int unset_rssi_reporter(struct sock *sk, u16 index,
1851 unsigned char *data, u16 len)
1852{
1853 struct mgmt_cp_unset_rssi_reporter *cp = (void *) data;
1854 struct hci_dev *hdev;
1855 struct hci_conn *conn;
1856 int err = 0;
1857
1858 if (len != sizeof(*cp))
1859 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1860 EINVAL);
1861
1862 hdev = hci_dev_get(index);
1863
1864 if (!hdev)
1865 return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1866 ENODEV);
1867
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001868 hci_dev_lock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001869
1870 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1871
1872 if (!conn) {
1873 err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER,
1874 ENOTCONN);
1875 goto failed;
1876 }
1877
1878 hci_conn_unset_rssi_reporter(conn);
1879
1880failed:
Archana Ramachandranf32d9822012-04-09 17:52:01 -07001881 hci_dev_unlock_bh(hdev);
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001882 hci_dev_put(hdev);
1883
1884 return err;
1885}
1886
Johan Hedbergb312b1612011-03-16 14:29:37 +02001887static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1888 u16 len)
1889{
1890 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1891 struct hci_cp_write_local_name hci_cp;
1892 struct hci_dev *hdev;
1893 struct pending_cmd *cmd;
1894 int err;
1895
1896 BT_DBG("");
1897
1898 if (len != sizeof(*mgmt_cp))
1899 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1900
1901 hdev = hci_dev_get(index);
1902 if (!hdev)
1903 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1904
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001905 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001906
1907 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1908 if (!cmd) {
1909 err = -ENOMEM;
1910 goto failed;
1911 }
1912
1913 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1914 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1915 &hci_cp);
1916 if (err < 0)
1917 mgmt_pending_remove(cmd);
1918
1919failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001920 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001921 hci_dev_put(hdev);
1922
1923 return err;
1924}
1925
Brian Gixa68668b2011-08-11 15:49:36 -07001926static void discovery_rsp(struct pending_cmd *cmd, void *data)
1927{
1928 struct mgmt_mode ev;
1929
1930 BT_DBG("");
1931 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1932 ev.val = 1;
1933 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1934 } else {
1935 ev.val = 0;
1936 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1937 NULL, 0);
1938 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001939 struct hci_dev *hdev = hci_dev_get(cmd->index);
1940 if (hdev) {
Brian Gix568dde92012-01-11 16:18:04 -08001941 del_timer(&hdev->disco_le_timer);
1942 del_timer(&hdev->disco_timer);
Brian Gix6e349d02011-11-28 14:51:14 -08001943 hci_dev_put(hdev);
1944 }
Brian Gixa68668b2011-08-11 15:49:36 -07001945 }
1946 }
1947
1948 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1949
1950 list_del(&cmd->list);
1951
1952 mgmt_pending_free(cmd);
1953}
1954
1955void mgmt_inquiry_started(u16 index)
1956{
1957 BT_DBG("");
1958 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1959 discovery_rsp, NULL);
1960}
1961
1962void mgmt_inquiry_complete_evt(u16 index, u8 status)
1963{
1964 struct hci_dev *hdev;
1965 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
Brian Gix568dde92012-01-11 16:18:04 -08001966 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001967 int err = -1;
1968
1969 BT_DBG("");
1970
1971 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001972
Brian Gixa68668b2011-08-11 15:49:36 -07001973 if (!hdev || !lmp_le_capable(hdev)) {
Brian Gixa68668b2011-08-11 15:49:36 -07001974
1975 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1976 discovery_terminated, NULL);
1977
1978 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001979
Brian Gix64bd5302011-09-08 11:35:48 -07001980 if (hdev)
1981 goto done;
1982 else
1983 return;
1984 }
Brian Gixa68668b2011-08-11 15:49:36 -07001985
Brian Gix568dde92012-01-11 16:18:04 -08001986 if (hdev->disco_state != SCAN_IDLE) {
Brian Gixa68668b2011-08-11 15:49:36 -07001987 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1988 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08001989 if (err >= 0) {
1990 mod_timer(&hdev->disco_le_timer, jiffies +
1991 msecs_to_jiffies(hdev->disco_int_phase * 1000));
1992 hdev->disco_state = SCAN_LE;
Brian Gixa68668b2011-08-11 15:49:36 -07001993 } else
Brian Gix568dde92012-01-11 16:18:04 -08001994 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07001995 }
1996
Brian Gix568dde92012-01-11 16:18:04 -08001997 if (hdev->disco_state == SCAN_IDLE)
1998 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
1999
Brian Gixa68668b2011-08-11 15:49:36 -07002000 if (err < 0)
2001 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2002 discovery_terminated, NULL);
2003
Brian Gix64bd5302011-09-08 11:35:48 -07002004done:
Brian Gixa68668b2011-08-11 15:49:36 -07002005 hci_dev_put(hdev);
2006}
2007
Brian Gix568dde92012-01-11 16:18:04 -08002008void mgmt_disco_timeout(unsigned long data)
Brian Gixa68668b2011-08-11 15:49:36 -07002009{
Brian Gix568dde92012-01-11 16:18:04 -08002010 struct hci_dev *hdev = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07002011 struct pending_cmd *cmd;
Brian Gix568dde92012-01-11 16:18:04 -08002012 struct mgmt_mode cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002013
Brian Gix568dde92012-01-11 16:18:04 -08002014 BT_DBG("hci%d", hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002015
Brian Gix568dde92012-01-11 16:18:04 -08002016 hdev = hci_dev_get(hdev->id);
Brian Gixa68668b2011-08-11 15:49:36 -07002017
Brian Gix568dde92012-01-11 16:18:04 -08002018 if (!hdev)
2019 return;
Brian Gixa68668b2011-08-11 15:49:36 -07002020
Brian Gix568dde92012-01-11 16:18:04 -08002021 hci_dev_lock_bh(hdev);
2022 del_timer(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002023
Brian Gix568dde92012-01-11 16:18:04 -08002024 if (hdev->disco_state != SCAN_IDLE) {
2025 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gixa68668b2011-08-11 15:49:36 -07002026
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302027 if (test_bit(HCI_UP, &hdev->flags)) {
2028 if (hdev->disco_state == SCAN_LE)
2029 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
Brian Gixa68668b2011-08-11 15:49:36 -07002030 sizeof(le_cp), &le_cp);
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302031 else
2032 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0,
2033 NULL);
2034 }
Brian Gix568dde92012-01-11 16:18:04 -08002035 hdev->disco_state = SCAN_IDLE;
Brian Gixa68668b2011-08-11 15:49:36 -07002036 }
Brian Gix568dde92012-01-11 16:18:04 -08002037
2038 mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
2039
2040 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
2041 if (cmd)
2042 mgmt_pending_remove(cmd);
2043
2044 hci_dev_unlock_bh(hdev);
2045 hci_dev_put(hdev);
2046}
2047
2048void mgmt_disco_le_timeout(unsigned long data)
2049{
2050 struct hci_dev *hdev = (void *)data;
2051 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2052
2053 BT_DBG("hci%d", hdev->id);
2054
2055 hdev = hci_dev_get(hdev->id);
2056
2057 if (!hdev)
2058 return;
2059
2060 hci_dev_lock_bh(hdev);
2061
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302062 if (test_bit(HCI_UP, &hdev->flags)) {
2063 if (hdev->disco_state == SCAN_LE)
2064 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2065 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002066
2067 /* re-start BR scan */
Bhasker Netia6e6a4f2012-01-27 15:25:43 +05302068 if (hdev->disco_state != SCAN_IDLE) {
2069 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2070 hdev->disco_int_phase *= 2;
2071 hdev->disco_int_count = 0;
2072 cp.num_rsp = (u8) hdev->disco_int_phase;
2073 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2074 hdev->disco_state = SCAN_BR;
2075 }
Brian Gix568dde92012-01-11 16:18:04 -08002076 }
2077
2078 hci_dev_unlock_bh(hdev);
2079 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002080}
2081
2082static int start_discovery(struct sock *sk, u16 index)
2083{
2084 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2085 struct hci_dev *hdev;
2086 struct pending_cmd *cmd;
2087 int err;
2088
2089 BT_DBG("");
2090
2091 hdev = hci_dev_get(index);
2092 if (!hdev)
2093 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2094
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002095 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002096
Brian Gix568dde92012-01-11 16:18:04 -08002097 if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
2098 err = -EBUSY;
2099 goto failed;
2100 }
2101
Brian Gixa68668b2011-08-11 15:49:36 -07002102 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2103 if (!cmd) {
2104 err = -ENOMEM;
2105 goto failed;
2106 }
2107
2108 /* If LE Capable, we will alternate between BR/EDR and LE */
2109 if (lmp_le_capable(hdev)) {
2110 struct hci_cp_le_set_scan_parameters le_cp;
2111
2112 /* Shorten BR scan params */
2113 cp.num_rsp = 1;
2114 cp.length /= 2;
2115
2116 /* Setup LE scan params */
2117 memset(&le_cp, 0, sizeof(le_cp));
2118 le_cp.type = 0x01; /* Active scanning */
2119 /* The recommended value for scan interval and window is
2120 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2121 le_cp.interval = cpu_to_le16(0x0012);
2122 le_cp.window = cpu_to_le16(0x0012);
2123 le_cp.own_bdaddr_type = 0; /* Public address */
2124 le_cp.filter = 0; /* Accept all adv packets */
2125
2126 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2127 sizeof(le_cp), &le_cp);
2128 }
2129
2130 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2131
2132 if (err < 0)
2133 mgmt_pending_remove(cmd);
2134 else if (lmp_le_capable(hdev)) {
Brian Gix474e0f22012-01-14 20:21:55 -08002135 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2136 if (!cmd)
2137 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index,
2138 NULL, 0);
Brian Gix568dde92012-01-11 16:18:04 -08002139 hdev->disco_int_phase = 1;
2140 hdev->disco_int_count = 0;
2141 hdev->disco_state = SCAN_BR;
Brian Gix568dde92012-01-11 16:18:04 -08002142 del_timer(&hdev->disco_le_timer);
2143 del_timer(&hdev->disco_timer);
2144 mod_timer(&hdev->disco_timer,
2145 jiffies + msecs_to_jiffies(20000));
Brian Gixa68668b2011-08-11 15:49:36 -07002146 }
2147
2148failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002149 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002150 hci_dev_put(hdev);
2151
Brian Gix568dde92012-01-11 16:18:04 -08002152 if (err < 0)
2153 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
2154
Brian Gixa68668b2011-08-11 15:49:36 -07002155 return err;
2156}
2157
2158static int stop_discovery(struct sock *sk, u16 index)
2159{
2160 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2161 struct mgmt_mode mode_cp = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07002162 struct hci_dev *hdev;
2163 struct pending_cmd *cmd = NULL;
2164 int err = -EPERM;
Brian Gix568dde92012-01-11 16:18:04 -08002165 u8 state;
Brian Gixa68668b2011-08-11 15:49:36 -07002166
2167 BT_DBG("");
2168
2169 hdev = hci_dev_get(index);
2170 if (!hdev)
2171 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2172
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002173 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002174
Brian Gix568dde92012-01-11 16:18:04 -08002175 state = hdev->disco_state;
2176 hdev->disco_state = SCAN_IDLE;
2177 del_timer(&hdev->disco_le_timer);
2178 del_timer(&hdev->disco_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002179
Brian Gix568dde92012-01-11 16:18:04 -08002180 if (state == SCAN_LE) {
Brian Gixa68668b2011-08-11 15:49:36 -07002181 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2182 sizeof(le_cp), &le_cp);
Brian Gix568dde92012-01-11 16:18:04 -08002183 if (err >= 0) {
2184 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
2185 discovery_terminated, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002186
Brian Gix568dde92012-01-11 16:18:04 -08002187 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2188 NULL, 0);
2189 }
Brian Gixa68668b2011-08-11 15:49:36 -07002190 }
2191
Brian Gix568dde92012-01-11 16:18:04 -08002192 if (err < 0)
2193 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07002194
Brian Gix568dde92012-01-11 16:18:04 -08002195 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
Brian Gixa68668b2011-08-11 15:49:36 -07002196 if (err < 0 && cmd)
2197 mgmt_pending_remove(cmd);
2198
2199 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2200
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002201 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002202 hci_dev_put(hdev);
2203
2204 if (err < 0)
2205 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2206 else
2207 return err;
2208}
2209
Szymon Jancc35938b2011-03-22 13:12:21 +01002210static int read_local_oob_data(struct sock *sk, u16 index)
2211{
2212 struct hci_dev *hdev;
2213 struct pending_cmd *cmd;
2214 int err;
2215
2216 BT_DBG("hci%u", index);
2217
2218 hdev = hci_dev_get(index);
2219 if (!hdev)
2220 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2221 ENODEV);
2222
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002223 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002224
2225 if (!test_bit(HCI_UP, &hdev->flags)) {
2226 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2227 ENETDOWN);
2228 goto unlock;
2229 }
2230
2231 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2232 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2233 EOPNOTSUPP);
2234 goto unlock;
2235 }
2236
2237 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2238 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2239 goto unlock;
2240 }
2241
2242 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2243 if (!cmd) {
2244 err = -ENOMEM;
2245 goto unlock;
2246 }
2247
2248 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2249 if (err < 0)
2250 mgmt_pending_remove(cmd);
2251
2252unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002253 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002254 hci_dev_put(hdev);
2255
2256 return err;
2257}
2258
Szymon Janc2763eda2011-03-22 13:12:22 +01002259static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2260 u16 len)
2261{
2262 struct hci_dev *hdev;
2263 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2264 int err;
2265
2266 BT_DBG("hci%u ", index);
2267
2268 if (len != sizeof(*cp))
2269 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2270 EINVAL);
2271
2272 hdev = hci_dev_get(index);
2273 if (!hdev)
2274 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2275 ENODEV);
2276
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002277 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002278
2279 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2280 cp->randomizer);
2281 if (err < 0)
2282 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2283 else
2284 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2285 0);
2286
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002287 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002288 hci_dev_put(hdev);
2289
2290 return err;
2291}
2292
2293static int remove_remote_oob_data(struct sock *sk, u16 index,
2294 unsigned char *data, u16 len)
2295{
2296 struct hci_dev *hdev;
2297 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2298 int err;
2299
2300 BT_DBG("hci%u ", index);
2301
2302 if (len != sizeof(*cp))
2303 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2304 EINVAL);
2305
2306 hdev = hci_dev_get(index);
2307 if (!hdev)
2308 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2309 ENODEV);
2310
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002311 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002312
2313 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2314 if (err < 0)
2315 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2316 -err);
2317 else
2318 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2319 NULL, 0);
2320
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002321 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002322 hci_dev_put(hdev);
2323
2324 return err;
2325}
2326
Johan Hedberg03811012010-12-08 00:21:06 +02002327int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2328{
2329 unsigned char *buf;
2330 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002331 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002332 int err;
2333
2334 BT_DBG("got %zu bytes", msglen);
2335
2336 if (msglen < sizeof(*hdr))
2337 return -EINVAL;
2338
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002339 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002340 if (!buf)
2341 return -ENOMEM;
2342
2343 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2344 err = -EFAULT;
2345 goto done;
2346 }
2347
2348 hdr = (struct mgmt_hdr *) buf;
2349 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002350 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002351 len = get_unaligned_le16(&hdr->len);
2352
2353 if (len != msglen - sizeof(*hdr)) {
2354 err = -EINVAL;
2355 goto done;
2356 }
2357
Brian Gixa68668b2011-08-11 15:49:36 -07002358 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002359 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002360 case MGMT_OP_READ_VERSION:
2361 err = read_version(sk);
2362 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002363 case MGMT_OP_READ_INDEX_LIST:
2364 err = read_index_list(sk);
2365 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002366 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002367 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002368 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002369 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002370 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002371 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002372 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002373 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002374 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002375 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2376 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2377 len);
2378 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002379 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002380 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002381 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002382 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002383 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002384 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002385 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002386 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002387 break;
2388 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002389 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002390 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002391 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002392 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002393 break;
2394 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002395 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002396 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002397 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002398 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002399 break;
2400 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002402 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002403 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002404 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002406 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002407 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002409 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002410 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002411 break;
2412 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002413 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002414 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002415 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002416 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002417 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002418 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002419 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002420 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002421 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002422 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002424 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2425 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002426 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002427 case MGMT_OP_SET_LOCAL_NAME:
2428 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2429 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002430 case MGMT_OP_START_DISCOVERY:
2431 err = start_discovery(sk, index);
2432 break;
2433 case MGMT_OP_STOP_DISCOVERY:
2434 err = stop_discovery(sk, index);
2435 break;
2436 case MGMT_OP_RESOLVE_NAME:
2437 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2438 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002439 case MGMT_OP_SET_CONNECTION_PARAMS:
2440 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2441 break;
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002442 case MGMT_OP_SET_RSSI_REPORTER:
2443 err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2444 break;
2445 case MGMT_OP_UNSET_RSSI_REPORTER:
2446 err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len);
2447 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002448 case MGMT_OP_READ_LOCAL_OOB_DATA:
2449 err = read_local_oob_data(sk, index);
2450 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002451 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2452 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2453 break;
2454 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2455 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2456 len);
2457 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302458 case MGMT_OP_ENCRYPT_LINK:
2459 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2460 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
Johan Hedberg03811012010-12-08 00:21:06 +02002462 default:
2463 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002464 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002465 break;
2466 }
2467
Johan Hedberge41d8b42010-12-13 21:07:03 +02002468 if (err < 0)
2469 goto done;
2470
Johan Hedberg03811012010-12-08 00:21:06 +02002471 err = msglen;
2472
2473done:
2474 kfree(buf);
2475 return err;
2476}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002477
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002478static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2479{
2480 u8 *status = data;
2481
2482 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2483 mgmt_pending_remove(cmd);
2484}
2485
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002486int mgmt_index_added(u16 index)
2487{
Brian Gixa68668b2011-08-11 15:49:36 -07002488 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002489 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002490}
2491
2492int mgmt_index_removed(u16 index)
2493{
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002494 u8 status = ENODEV;
2495
Brian Gixa68668b2011-08-11 15:49:36 -07002496 BT_DBG("%d", index);
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002497
2498 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2499
Szymon Janc4e51eae2011-02-25 19:05:48 +01002500 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002501}
2502
Johan Hedberg73f22f62010-12-29 16:00:25 +02002503struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002504 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002505 struct sock *sk;
2506};
2507
Johan Hedberg72a734e2010-12-30 00:38:22 +02002508static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002509{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002510 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002511 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002512
Johan Hedberg72a734e2010-12-30 00:38:22 +02002513 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002514 return;
2515
Johan Hedberg053f0212011-01-26 13:07:10 +02002516 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002517
2518 list_del(&cmd->list);
2519
2520 if (match->sk == NULL) {
2521 match->sk = cmd->sk;
2522 sock_hold(match->sk);
2523 }
2524
2525 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002526}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002527
2528int mgmt_powered(u16 index, u8 powered)
2529{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002530 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002531 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002532 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002533
Brian Gixa68668b2011-08-11 15:49:36 -07002534 BT_DBG("hci%u %d", index, powered);
2535
Johan Hedberg72a734e2010-12-30 00:38:22 +02002536 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002537
Johan Hedberg931bc4e2011-11-03 14:40:33 +02002538 if (!powered) {
2539 u8 status = ENETDOWN;
2540 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2541 }
2542
Johan Hedberg72a734e2010-12-30 00:38:22 +02002543 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002544
Szymon Janc4e51eae2011-02-25 19:05:48 +01002545 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002546
2547 if (match.sk)
2548 sock_put(match.sk);
2549
2550 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002551}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002552
Johan Hedberg73f22f62010-12-29 16:00:25 +02002553int mgmt_discoverable(u16 index, u8 discoverable)
2554{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002555 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002556 struct cmd_lookup match = { discoverable, NULL };
2557 int ret;
2558
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002559 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002560
Johan Hedberg72a734e2010-12-30 00:38:22 +02002561 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002562
Szymon Janc4e51eae2011-02-25 19:05:48 +01002563 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2564 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002565
2566 if (match.sk)
2567 sock_put(match.sk);
2568
2569 return ret;
2570}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002571
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002572int mgmt_connectable(u16 index, u8 connectable)
2573{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002574 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002575 struct cmd_lookup match = { connectable, NULL };
2576 int ret;
2577
Johan Hedberg72a734e2010-12-30 00:38:22 +02002578 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002579
Johan Hedberg72a734e2010-12-30 00:38:22 +02002580 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002581
Szymon Janc4e51eae2011-02-25 19:05:48 +01002582 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002583
2584 if (match.sk)
2585 sock_put(match.sk);
2586
2587 return ret;
2588}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002589
Brian Gixa68668b2011-08-11 15:49:36 -07002590int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002591{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002592 struct mgmt_ev_new_key *ev;
2593 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002594
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002595 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2596 ev = kzalloc(total, GFP_ATOMIC);
2597 if (!ev)
2598 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002599
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002600 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002601 ev->key.addr_type = key->addr_type;
2602 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002603 memcpy(ev->key.val, key->val, 16);
2604 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002605 ev->key.auth = key->auth;
2606 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002607 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002608
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002609 memcpy(ev->key.data, key->data, key->dlen);
2610
2611 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2612
2613 kfree(ev);
2614
2615 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002616}
Johan Hedbergf7520542011-01-20 12:34:39 +02002617
Brian Gix2e2f50d2011-09-13 12:36:04 -07002618int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002619{
2620 struct mgmt_ev_connected ev;
2621
Johan Hedbergf7520542011-01-20 12:34:39 +02002622 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002623 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002624
Szymon Janc4e51eae2011-02-25 19:05:48 +01002625 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002626}
2627
Johan Hedberg8962ee72011-01-20 12:40:27 +02002628static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2629{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002630 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002631 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002632 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002633
Johan Hedberga38528f2011-01-22 06:46:43 +02002634 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002635
Szymon Janc4e51eae2011-02-25 19:05:48 +01002636 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002637
2638 *sk = cmd->sk;
2639 sock_hold(*sk);
2640
Johan Hedberga664b5b2011-02-19 12:06:02 -03002641 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002642}
2643
Johan Hedbergf7520542011-01-20 12:34:39 +02002644int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2645{
2646 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002647 struct sock *sk = NULL;
2648 int err;
2649
2650 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002651
Johan Hedbergf7520542011-01-20 12:34:39 +02002652 bacpy(&ev.bdaddr, bdaddr);
2653
Szymon Janc4e51eae2011-02-25 19:05:48 +01002654 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002655
2656 if (sk)
2657 sock_put(sk);
2658
2659 return err;
2660}
2661
2662int mgmt_disconnect_failed(u16 index)
2663{
2664 struct pending_cmd *cmd;
2665 int err;
2666
2667 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2668 if (!cmd)
2669 return -ENOENT;
2670
Szymon Janc4e51eae2011-02-25 19:05:48 +01002671 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002672
Johan Hedberga664b5b2011-02-19 12:06:02 -03002673 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002674
2675 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002676}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002677
2678int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2679{
2680 struct mgmt_ev_connect_failed ev;
2681
Johan Hedberg17d5c042011-01-22 06:09:08 +02002682 bacpy(&ev.bdaddr, bdaddr);
2683 ev.status = status;
2684
Szymon Janc4e51eae2011-02-25 19:05:48 +01002685 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002686}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002689{
2690 struct mgmt_ev_pin_code_request ev;
2691
Brian Gixa68668b2011-08-11 15:49:36 -07002692 BT_DBG("hci%u", index);
2693
Johan Hedberg980e1a52011-01-22 06:10:07 +02002694 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002695 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002696
Szymon Janc4e51eae2011-02-25 19:05:48 +01002697 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2698 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002699}
2700
2701int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2702{
2703 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002704 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002705 int err;
2706
2707 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2708 if (!cmd)
2709 return -ENOENT;
2710
Johan Hedbergac56fb12011-02-19 12:05:59 -03002711 bacpy(&rp.bdaddr, bdaddr);
2712 rp.status = status;
2713
Szymon Janc4e51eae2011-02-25 19:05:48 +01002714 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2715 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002716
Johan Hedberga664b5b2011-02-19 12:06:02 -03002717 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
2719 return err;
2720}
2721
2722int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2723{
2724 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002725 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726 int err;
2727
2728 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2729 if (!cmd)
2730 return -ENOENT;
2731
Johan Hedbergac56fb12011-02-19 12:05:59 -03002732 bacpy(&rp.bdaddr, bdaddr);
2733 rp.status = status;
2734
Szymon Janc4e51eae2011-02-25 19:05:48 +01002735 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2736 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002737
Johan Hedberga664b5b2011-02-19 12:06:02 -03002738 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002739
2740 return err;
2741}
Johan Hedberga5c29682011-02-19 12:05:57 -03002742
Brian Gixa68668b2011-08-11 15:49:36 -07002743int mgmt_user_confirm_request(u16 index, u8 event,
2744 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002745{
2746 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002747 struct hci_conn *conn = NULL;
2748 struct hci_dev *hdev;
2749 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2750
2751 BT_DBG("hci%u", index);
2752
2753 hdev = hci_dev_get(index);
2754
Brian Gix64bd5302011-09-08 11:35:48 -07002755 if (!hdev)
2756 return -ENODEV;
2757
Brian Gix64bd5302011-09-08 11:35:48 -07002758 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002759
2760 ev.auto_confirm = 0;
2761
2762 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2763 goto no_auto_confirm;
2764
2765 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2766 rem_cap = conn->remote_cap;
2767 loc_mitm = conn->auth_type & 0x01;
2768 rem_mitm = conn->remote_auth & 0x01;
2769
Brian Gixdbf59292011-11-11 15:45:17 -08002770 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2771 conn->auth_initiator && rem_cap == 0x03)
2772 ev.auto_confirm = 1;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302773 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
2774 if (!loc_mitm && !rem_mitm)
2775 value = 0;
Brian Gixa68668b2011-08-11 15:49:36 -07002776 goto no_auto_confirm;
AnubhavGupta07c2a0f2012-02-16 19:03:59 +05302777 }
Brian Gixa68668b2011-08-11 15:49:36 -07002778
2779
2780 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2781 ev.auto_confirm = 1;
2782
2783no_auto_confirm:
2784 bacpy(&ev.bdaddr, bdaddr);
2785 ev.event = event;
2786 put_unaligned_le32(value, &ev.value);
2787
Brian Gix64bd5302011-09-08 11:35:48 -07002788 hci_dev_put(hdev);
2789
Brian Gixa68668b2011-08-11 15:49:36 -07002790 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2791 NULL);
2792}
2793
2794int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2795{
2796 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002797
2798 BT_DBG("hci%u", index);
2799
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002801
Brian Gixa68668b2011-08-11 15:49:36 -07002802 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002803 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002804}
2805
2806static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2807 u8 opcode)
2808{
2809 struct pending_cmd *cmd;
2810 struct mgmt_rp_user_confirm_reply rp;
2811 int err;
2812
2813 cmd = mgmt_pending_find(opcode, index);
2814 if (!cmd)
2815 return -ENOENT;
2816
Johan Hedberga5c29682011-02-19 12:05:57 -03002817 bacpy(&rp.bdaddr, bdaddr);
2818 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002819 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002820
Johan Hedberga664b5b2011-02-19 12:06:02 -03002821 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002822
2823 return err;
2824}
2825
2826int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2827{
2828 return confirm_reply_complete(index, bdaddr, status,
2829 MGMT_OP_USER_CONFIRM_REPLY);
2830}
2831
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002832int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002833{
2834 return confirm_reply_complete(index, bdaddr, status,
2835 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2836}
Johan Hedberg2a611692011-02-19 12:06:00 -03002837
2838int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2839{
2840 struct mgmt_ev_auth_failed ev;
2841
Johan Hedberg2a611692011-02-19 12:06:00 -03002842 bacpy(&ev.bdaddr, bdaddr);
2843 ev.status = status;
2844
Szymon Janc4e51eae2011-02-25 19:05:48 +01002845 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002846}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002847
2848int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2849{
2850 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002851 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002852 struct mgmt_cp_set_local_name ev;
2853 int err;
2854
2855 memset(&ev, 0, sizeof(ev));
2856 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2857
2858 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2859 if (!cmd)
2860 goto send_event;
2861
2862 if (status) {
2863 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2864 goto failed;
2865 }
2866
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002867 hdev = hci_dev_get(index);
2868 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002869 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002870 hci_dev_put(hdev);
2871 }
2872
Johan Hedbergb312b1612011-03-16 14:29:37 +02002873 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2874 sizeof(ev));
2875 if (err < 0)
2876 goto failed;
2877
2878send_event:
2879 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2880 cmd ? cmd->sk : NULL);
2881
2882failed:
2883 if (cmd)
2884 mgmt_pending_remove(cmd);
2885 return err;
2886}
Szymon Jancc35938b2011-03-22 13:12:21 +01002887
2888int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2889 u8 status)
2890{
2891 struct pending_cmd *cmd;
2892 int err;
2893
2894 BT_DBG("hci%u status %u", index, status);
2895
2896 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2897 if (!cmd)
2898 return -ENOENT;
2899
2900 if (status) {
2901 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2902 EIO);
2903 } else {
2904 struct mgmt_rp_read_local_oob_data rp;
2905
2906 memcpy(rp.hash, hash, sizeof(rp.hash));
2907 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2908
2909 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2910 &rp, sizeof(rp));
2911 }
2912
2913 mgmt_pending_remove(cmd);
2914
2915 return err;
2916}
Johan Hedberge17acd42011-03-30 23:57:16 +03002917
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002918void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
2919 u16 handle, u8 status)
2920{
2921 struct mgmt_ev_rssi_update ev;
2922 struct hci_conn *conn;
2923 struct hci_dev *hdev;
2924
2925 if (status)
2926 return;
2927
2928 hdev = hci_dev_get(index);
2929 conn = hci_conn_hash_lookup_handle(hdev, handle);
2930
2931 if (!conn)
2932 return;
2933
2934 BT_DBG("rssi_update_thresh_exceed : %d ",
2935 conn->rssi_update_thresh_exceed);
2936 BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ",
2937 conn->rssi_threshold, rssi);
2938
2939 if (conn->rssi_update_thresh_exceed == 1) {
2940 BT_DBG("rssi_update_thresh_exceed == 1");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002941 if (rssi > conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002942 memset(&ev, 0, sizeof(ev));
2943 bacpy(&ev.bdaddr, bdaddr);
2944 ev.rssi = rssi;
2945 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2946 sizeof(ev), NULL);
2947 } else {
2948 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2949 conn->rssi_update_interval,
2950 conn->rssi_update_thresh_exceed);
2951 }
2952 } else {
2953 BT_DBG("rssi_update_thresh_exceed == 0");
Archana Ramachandran5d332a42012-03-22 15:35:34 -07002954 if (rssi < conn->rssi_threshold) {
Archana Ramachandran26a752b2011-12-20 11:27:40 -08002955 memset(&ev, 0, sizeof(ev));
2956 bacpy(&ev.bdaddr, bdaddr);
2957 ev.rssi = rssi;
2958 mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev,
2959 sizeof(ev), NULL);
2960 } else {
2961 hci_conn_set_rssi_reporter(conn, conn->rssi_threshold,
2962 conn->rssi_update_interval,
2963 conn->rssi_update_thresh_exceed);
2964 }
2965 }
2966}
2967
2968
Brian Gixa68668b2011-08-11 15:49:36 -07002969int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2970 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002971{
2972 struct mgmt_ev_device_found ev;
Brian Gix568dde92012-01-11 16:18:04 -08002973 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07002974 int err;
2975
2976 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002977
2978 memset(&ev, 0, sizeof(ev));
2979
2980 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002981 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002982 ev.type = type;
2983 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002984
Brian Gixa68668b2011-08-11 15:49:36 -07002985 if (dev_class)
2986 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002987
Brian Gixa68668b2011-08-11 15:49:36 -07002988 if (eir && eir_len)
2989 memcpy(ev.eir, eir, eir_len);
2990
2991 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2992
2993 if (err < 0)
2994 return err;
2995
Brian Gix568dde92012-01-11 16:18:04 -08002996 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002997
Brian Gix568dde92012-01-11 16:18:04 -08002998 if (!hdev)
2999 return 0;
Brian Gix64bd5302011-09-08 11:35:48 -07003000
Brian Gix568dde92012-01-11 16:18:04 -08003001 if (hdev->disco_state == SCAN_IDLE)
3002 goto done;
3003
3004 hdev->disco_int_count++;
3005
3006 if (hdev->disco_int_count >= hdev->disco_int_phase) {
3007 /* Inquiry scan for General Discovery LAP */
3008 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
3009 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
3010
3011 hdev->disco_int_phase *= 2;
3012 hdev->disco_int_count = 0;
3013 if (hdev->disco_state == SCAN_LE) {
3014 /* cancel LE scan */
3015 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
3016 sizeof(le_cp), &le_cp);
3017 /* start BR scan */
3018 cp.num_rsp = (u8) hdev->disco_int_phase;
3019 hci_send_cmd(hdev, HCI_OP_INQUIRY,
3020 sizeof(cp), &cp);
3021 hdev->disco_state = SCAN_BR;
3022 del_timer_sync(&hdev->disco_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07003023 }
3024 }
3025
Brian Gix568dde92012-01-11 16:18:04 -08003026done:
3027 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07003028 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03003029}
Johan Hedberga88a9652011-03-30 13:18:12 +03003030
Brian Gixa68668b2011-08-11 15:49:36 -07003031
3032int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03003033{
3034 struct mgmt_ev_remote_name ev;
3035
3036 memset(&ev, 0, sizeof(ev));
3037
3038 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07003039 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03003040 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3041
3042 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
3043}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05303044
3045int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
3046{
3047 struct mgmt_ev_encrypt_change ev;
3048
3049 BT_DBG("hci%u", index);
3050
3051 bacpy(&ev.bdaddr, bdaddr);
3052 ev.status = status;
3053
3054 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
3055 NULL);
3056}
3057
Srinivas Krovvidi0916aed2011-12-20 12:06:34 +05303058int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
3059{
3060 struct mgmt_ev_remote_class ev;
3061
3062 memset(&ev, 0, sizeof(ev));
3063
3064 bacpy(&ev.bdaddr, bdaddr);
3065 memcpy(ev.dev_class, dev_class, 3);
3066
3067 return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
3068}
Srinivas Krovvidid352b262012-01-12 19:46:26 +05303069
3070int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
3071 u16 sub_ver)
3072{
3073 struct mgmt_ev_remote_version ev;
3074
3075 memset(&ev, 0, sizeof(ev));
3076
3077 bacpy(&ev.bdaddr, bdaddr);
3078 ev.lmp_ver = ver;
3079 ev.manufacturer = mnf;
3080 ev.lmp_subver = sub_ver;
3081
3082 return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
3083}
Sunny Kapdif3caf882012-02-25 19:27:09 -08003084
3085int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
3086{
3087 struct mgmt_ev_remote_features ev;
3088
3089 memset(&ev, 0, sizeof(ev));
3090
3091 bacpy(&ev.bdaddr, bdaddr);
3092 memcpy(ev.features, features, sizeof(ev.features));
3093
3094 return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
3095 NULL);
3096}