blob: 3b63aee1828c7243572bdbfd5099c0221619f9c8 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070030#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020031#include <net/bluetooth/mgmt.h>
Brian Gixa68668b2011-08-11 15:49:36 -070032#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020033
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Brian Gixa68668b2011-08-11 15:49:36 -070037enum scan_mode {
38 SCAN_IDLE,
39 SCAN_LE,
40 SCAN_BR
41};
42
43struct disco_interleave {
44 struct timer_list timer;
45 struct timer_list le_timer;
46 u16 index;
47 enum scan_mode mode;
48 int int_phase;
49 int int_count;
50};
51
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020052struct pending_cmd {
53 struct list_head list;
54 __u16 opcode;
55 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010056 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030058 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020059};
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020062
Szymon Janc4e51eae2011-02-25 19:05:48 +010063static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020064{
65 struct sk_buff *skb;
66 struct mgmt_hdr *hdr;
67 struct mgmt_ev_cmd_status *ev;
68
Szymon Janc34eb5252011-02-28 14:10:08 +010069 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020070
71 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
72 if (!skb)
73 return -ENOMEM;
74
75 hdr = (void *) skb_put(skb, sizeof(*hdr));
76
77 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010078 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020079 hdr->len = cpu_to_le16(sizeof(*ev));
80
81 ev = (void *) skb_put(skb, sizeof(*ev));
82 ev->status = status;
83 put_unaligned_le16(cmd, &ev->opcode);
84
85 if (sock_queue_rcv_skb(sk, skb) < 0)
86 kfree_skb(skb);
87
88 return 0;
89}
90
Szymon Janc4e51eae2011-02-25 19:05:48 +010091static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
92 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020093{
94 struct sk_buff *skb;
95 struct mgmt_hdr *hdr;
96 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020097
98 BT_DBG("sock %p", sk);
99
Johan Hedberga38528f2011-01-22 06:46:43 +0200100 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101 if (!skb)
102 return -ENOMEM;
103
104 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200105
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100107 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200108 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200109
Johan Hedberga38528f2011-01-22 06:46:43 +0200110 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
111 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100112
113 if (rp)
114 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200115
116 if (sock_queue_rcv_skb(sk, skb) < 0)
117 kfree_skb(skb);
118
119 return 0;
120}
121
Johan Hedberga38528f2011-01-22 06:46:43 +0200122static int read_version(struct sock *sk)
123{
124 struct mgmt_rp_read_version rp;
125
126 BT_DBG("sock %p", sk);
127
128 rp.version = MGMT_VERSION;
129 put_unaligned_le16(MGMT_REVISION, &rp.revision);
130
Szymon Janc4e51eae2011-02-25 19:05:48 +0100131 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
132 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200133}
134
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200135static int read_index_list(struct sock *sk)
136{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 struct mgmt_rp_read_index_list *rp;
138 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200139 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200141 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142
143 BT_DBG("sock %p", sk);
144
145 read_lock(&hci_dev_list_lock);
146
147 count = 0;
148 list_for_each(p, &hci_dev_list) {
149 count++;
150 }
151
Johan Hedberga38528f2011-01-22 06:46:43 +0200152 rp_len = sizeof(*rp) + (2 * count);
153 rp = kmalloc(rp_len, GFP_ATOMIC);
154 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100155 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100157 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158
Brian Gixa68668b2011-08-11 15:49:36 -0700159 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200160
161 i = 0;
162 list_for_each(p, &hci_dev_list) {
163 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200164
165 hci_del_off_timer(d);
166
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200167 set_bit(HCI_MGMT, &d->flags);
168
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200169 if (test_bit(HCI_SETUP, &d->flags))
170 continue;
171
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200172 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700173 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200174 BT_DBG("Added hci%u", d->id);
175 }
176
177 read_unlock(&hci_dev_list_lock);
178
Szymon Janc4e51eae2011-02-25 19:05:48 +0100179 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
180 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200181
Johan Hedberga38528f2011-01-22 06:46:43 +0200182 kfree(rp);
183
184 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200185}
186
Szymon Janc4e51eae2011-02-25 19:05:48 +0100187static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200188{
Johan Hedberga38528f2011-01-22 06:46:43 +0200189 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200190 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200193
Szymon Janc4e51eae2011-02-25 19:05:48 +0100194 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200195 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200198 hci_del_off_timer(hdev);
199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200202 set_bit(HCI_MGMT, &hdev->flags);
203
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200204 memset(&rp, 0, sizeof(rp));
205
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207
Johan Hedberga38528f2011-01-22 06:46:43 +0200208 rp.powered = test_bit(HCI_UP, &hdev->flags);
209 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
210 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
211 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
213 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200216 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200218 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200219
Johan Hedberga38528f2011-01-22 06:46:43 +0200220 bacpy(&rp.bdaddr, &hdev->bdaddr);
221 memcpy(rp.features, hdev->features, 8);
222 memcpy(rp.dev_class, hdev->dev_class, 3);
223 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
224 rp.hci_ver = hdev->hci_ver;
225 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200227 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200230 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200231
Szymon Janc4e51eae2011-02-25 19:05:48 +0100232 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200233}
234
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200235static void mgmt_pending_free(struct pending_cmd *cmd)
236{
Brian Gixa68668b2011-08-11 15:49:36 -0700237 BT_DBG("%d", cmd->opcode);
238
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100240 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 kfree(cmd);
242}
243
Johan Hedberg366a0332011-02-19 12:05:55 -0300244static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
245 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200246{
247 struct pending_cmd *cmd;
248
Brian Gixa68668b2011-08-11 15:49:36 -0700249 BT_DBG("%d", opcode);
250
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200251 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
252 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300253 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200254
255 cmd->opcode = opcode;
256 cmd->index = index;
257
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100258 cmd->param = kmalloc(len, GFP_ATOMIC);
259 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200260 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300261 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200262 }
263
Szymon Janc8fce6352011-03-22 13:12:20 +0100264 if (data)
265 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200266
267 cmd->sk = sk;
268 sock_hold(sk);
269
270 list_add(&cmd->list, &cmd_list);
271
Johan Hedberg366a0332011-02-19 12:05:55 -0300272 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200273}
274
275static void mgmt_pending_foreach(u16 opcode, int index,
276 void (*cb)(struct pending_cmd *cmd, void *data),
277 void *data)
278{
279 struct list_head *p, *n;
280
Brian Gixa68668b2011-08-11 15:49:36 -0700281 BT_DBG(" %d", opcode);
282
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200283 list_for_each_safe(p, n, &cmd_list) {
284 struct pending_cmd *cmd;
285
286 cmd = list_entry(p, struct pending_cmd, list);
287
288 if (cmd->opcode != opcode)
289 continue;
290
291 if (index >= 0 && cmd->index != index)
292 continue;
293
294 cb(cmd, data);
295 }
296}
297
298static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
299{
300 struct list_head *p;
301
Brian Gixa68668b2011-08-11 15:49:36 -0700302 BT_DBG(" %d", opcode);
303
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 list_for_each(p, &cmd_list) {
305 struct pending_cmd *cmd;
306
307 cmd = list_entry(p, struct pending_cmd, list);
308
309 if (cmd->opcode != opcode)
310 continue;
311
312 if (index >= 0 && cmd->index != index)
313 continue;
314
315 return cmd;
316 }
317
318 return NULL;
319}
320
Johan Hedberga664b5b2011-02-19 12:06:02 -0300321static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200322{
Brian Gixa68668b2011-08-11 15:49:36 -0700323 BT_DBG(" %d", cmd->opcode);
324
Johan Hedberg73f22f62010-12-29 16:00:25 +0200325 list_del(&cmd->list);
326 mgmt_pending_free(cmd);
327}
328
Szymon Janc4e51eae2011-02-25 19:05:48 +0100329static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200331 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335
336 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Szymon Janc4e51eae2011-02-25 19:05:48 +0100338 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100340 if (len != sizeof(*cp))
341 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
342
Szymon Janc4e51eae2011-02-25 19:05:48 +0100343 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100345 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348
349 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200350 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352 goto failed;
353 }
354
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
356 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200357 goto failed;
358 }
359
Szymon Janc4e51eae2011-02-25 19:05:48 +0100360 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300361 if (!cmd) {
362 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300364 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200365
Johan Hedberg72a734e2010-12-30 00:38:22 +0200366 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200367 queue_work(hdev->workqueue, &hdev->power_on);
368 else
369 queue_work(hdev->workqueue, &hdev->power_off);
370
Johan Hedberg366a0332011-02-19 12:05:55 -0300371 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200372
373failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300376 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377}
378
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
380 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200382 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200383 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300384 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 u8 scan;
386 int err;
387
388 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200389
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100392 if (len != sizeof(*cp))
393 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
394
Szymon Janc4e51eae2011-02-25 19:05:48 +0100395 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100397 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400
401 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100402 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403 goto failed;
404 }
405
Szymon Janc4e51eae2011-02-25 19:05:48 +0100406 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
407 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
408 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200409 goto failed;
410 }
411
Johan Hedberg72a734e2010-12-30 00:38:22 +0200412 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200413 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100414 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200415 goto failed;
416 }
417
Szymon Janc4e51eae2011-02-25 19:05:48 +0100418 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300419 if (!cmd) {
420 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200421 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300422 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200423
424 scan = SCAN_PAGE;
425
Johan Hedberg72a734e2010-12-30 00:38:22 +0200426 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200427 scan |= SCAN_INQUIRY;
428
429 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
430 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300431 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200432
433failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200435 hci_dev_put(hdev);
436
437 return err;
438}
439
Szymon Janc4e51eae2011-02-25 19:05:48 +0100440static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
441 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200443 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300445 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 u8 scan;
447 int err;
448
449 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450
Szymon Janc4e51eae2011-02-25 19:05:48 +0100451 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100453 if (len != sizeof(*cp))
454 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
455
Szymon Janc4e51eae2011-02-25 19:05:48 +0100456 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100458 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
462 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100463 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464 goto failed;
465 }
466
Szymon Janc4e51eae2011-02-25 19:05:48 +0100467 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
468 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
469 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200470 goto failed;
471 }
472
Johan Hedberg72a734e2010-12-30 00:38:22 +0200473 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100474 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200475 goto failed;
476 }
477
Szymon Janc4e51eae2011-02-25 19:05:48 +0100478 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300479 if (!cmd) {
480 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200481 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300482 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200483
Johan Hedberg72a734e2010-12-30 00:38:22 +0200484 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200485 scan = SCAN_PAGE;
486 else
487 scan = 0;
488
489 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
490 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300491 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200492
493failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200495 hci_dev_put(hdev);
496
497 return err;
498}
499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
501 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200502{
503 struct sk_buff *skb;
504 struct mgmt_hdr *hdr;
505
Brian Gixa68668b2011-08-11 15:49:36 -0700506 BT_DBG("hci%d %d", index, event);
507
Johan Hedbergc542a062011-01-26 13:11:03 +0200508 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
509 if (!skb)
510 return -ENOMEM;
511
512 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
513
514 hdr = (void *) skb_put(skb, sizeof(*hdr));
515 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517 hdr->len = cpu_to_le16(data_len);
518
Szymon Janc4e51eae2011-02-25 19:05:48 +0100519 if (data)
520 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
522 hci_send_to_sock(NULL, skb, skip_sk);
523 kfree_skb(skb);
524
525 return 0;
526}
527
Johan Hedberg053f0212011-01-26 13:07:10 +0200528static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
529{
Johan Hedberga38528f2011-01-22 06:46:43 +0200530 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200531
Johan Hedberga38528f2011-01-22 06:46:43 +0200532 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200533
Szymon Janc4e51eae2011-02-25 19:05:48 +0100534 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200535}
536
Szymon Janc4e51eae2011-02-25 19:05:48 +0100537static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
538 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200539{
540 struct mgmt_mode *cp, ev;
541 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 int err;
543
544 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200545
Szymon Janc4e51eae2011-02-25 19:05:48 +0100546 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200547
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100548 if (len != sizeof(*cp))
549 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
550
Szymon Janc4e51eae2011-02-25 19:05:48 +0100551 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200552 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100553 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200556
557 if (cp->val)
558 set_bit(HCI_PAIRABLE, &hdev->flags);
559 else
560 clear_bit(HCI_PAIRABLE, &hdev->flags);
561
Szymon Janc4e51eae2011-02-25 19:05:48 +0100562 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200563 if (err < 0)
564 goto failed;
565
Johan Hedbergc542a062011-01-26 13:11:03 +0200566 ev.val = cp->val;
567
Szymon Janc4e51eae2011-02-25 19:05:48 +0100568 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200569
570failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200572 hci_dev_put(hdev);
573
574 return err;
575}
576
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300577#define EIR_FLAGS 0x01 /* flags */
578#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
579#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
580#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
581#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
582#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
583#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
584#define EIR_NAME_SHORT 0x08 /* shortened local name */
585#define EIR_NAME_COMPLETE 0x09 /* complete local name */
586#define EIR_TX_POWER 0x0A /* transmit power level */
587#define EIR_DEVICE_ID 0x10 /* device ID */
588
589#define PNP_INFO_SVCLASS_ID 0x1200
590
591static u8 bluetooth_base_uuid[] = {
592 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
593 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594};
595
596static u16 get_uuid16(u8 *uuid128)
597{
598 u32 val;
599 int i;
600
601 for (i = 0; i < 12; i++) {
602 if (bluetooth_base_uuid[i] != uuid128[i])
603 return 0;
604 }
605
606 memcpy(&val, &uuid128[12], 4);
607
608 val = le32_to_cpu(val);
609 if (val > 0xffff)
610 return 0;
611
612 return (u16) val;
613}
614
615static void create_eir(struct hci_dev *hdev, u8 *data)
616{
617 u8 *ptr = data;
618 u16 eir_len = 0;
619 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
620 int i, truncated = 0;
621 struct list_head *p;
622 size_t name_len;
623
624 name_len = strlen(hdev->dev_name);
625
626 if (name_len > 0) {
627 /* EIR Data type */
628 if (name_len > 48) {
629 name_len = 48;
630 ptr[1] = EIR_NAME_SHORT;
631 } else
632 ptr[1] = EIR_NAME_COMPLETE;
633
634 /* EIR Data length */
635 ptr[0] = name_len + 1;
636
637 memcpy(ptr + 2, hdev->dev_name, name_len);
638
639 eir_len += (name_len + 2);
640 ptr += (name_len + 2);
641 }
642
643 memset(uuid16_list, 0, sizeof(uuid16_list));
644
645 /* Group all UUID16 types */
646 list_for_each(p, &hdev->uuids) {
647 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
648 u16 uuid16;
649
650 uuid16 = get_uuid16(uuid->uuid);
651 if (uuid16 == 0)
652 return;
653
654 if (uuid16 < 0x1100)
655 continue;
656
657 if (uuid16 == PNP_INFO_SVCLASS_ID)
658 continue;
659
660 /* Stop if not enough space to put next UUID */
661 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
662 truncated = 1;
663 break;
664 }
665
666 /* Check for duplicates */
667 for (i = 0; uuid16_list[i] != 0; i++)
668 if (uuid16_list[i] == uuid16)
669 break;
670
671 if (uuid16_list[i] == 0) {
672 uuid16_list[i] = uuid16;
673 eir_len += sizeof(u16);
674 }
675 }
676
677 if (uuid16_list[0] != 0) {
678 u8 *length = ptr;
679
680 /* EIR Data type */
681 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
682
683 ptr += 2;
684 eir_len += 2;
685
686 for (i = 0; uuid16_list[i] != 0; i++) {
687 *ptr++ = (uuid16_list[i] & 0x00ff);
688 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
689 }
690
691 /* EIR Data length */
692 *length = (i * sizeof(u16)) + 1;
693 }
694}
695
696static int update_eir(struct hci_dev *hdev)
697{
698 struct hci_cp_write_eir cp;
699
700 if (!(hdev->features[6] & LMP_EXT_INQ))
701 return 0;
702
703 if (hdev->ssp_mode == 0)
704 return 0;
705
706 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
707 return 0;
708
709 memset(&cp, 0, sizeof(cp));
710
711 create_eir(hdev, cp.data);
712
713 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
714 return 0;
715
716 memcpy(hdev->eir, cp.data, sizeof(cp.data));
717
718 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
719}
720
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200721static u8 get_service_classes(struct hci_dev *hdev)
722{
723 struct list_head *p;
724 u8 val = 0;
725
726 list_for_each(p, &hdev->uuids) {
727 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
728
729 val |= uuid->svc_hint;
730 }
731
732 return val;
733}
734
735static int update_class(struct hci_dev *hdev)
736{
737 u8 cod[3];
738
739 BT_DBG("%s", hdev->name);
740
741 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
742 return 0;
743
744 cod[0] = hdev->minor_class;
745 cod[1] = hdev->major_class;
746 cod[2] = get_service_classes(hdev);
747
748 if (memcmp(cod, hdev->dev_class, 3) == 0)
749 return 0;
750
751 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
752}
753
Szymon Janc4e51eae2011-02-25 19:05:48 +0100754static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200755{
756 struct mgmt_cp_add_uuid *cp;
757 struct hci_dev *hdev;
758 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200759 int err;
760
761 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200762
Szymon Janc4e51eae2011-02-25 19:05:48 +0100763 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200764
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100765 if (len != sizeof(*cp))
766 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100770 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200773
774 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
775 if (!uuid) {
776 err = -ENOMEM;
777 goto failed;
778 }
779
780 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782
783 list_add(&uuid->list, &hdev->uuids);
784
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200785 err = update_class(hdev);
786 if (err < 0)
787 goto failed;
788
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300789 err = update_eir(hdev);
790 if (err < 0)
791 goto failed;
792
Szymon Janc4e51eae2011-02-25 19:05:48 +0100793 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
795failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200797 hci_dev_put(hdev);
798
799 return err;
800}
801
Szymon Janc4e51eae2011-02-25 19:05:48 +0100802static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200803{
804 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100805 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200806 struct hci_dev *hdev;
807 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 +0200808 int err, found;
809
810 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200811
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200813
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100814 if (len != sizeof(*cp))
815 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
816
Szymon Janc4e51eae2011-02-25 19:05:48 +0100817 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200818 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200822
823 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
824 err = hci_uuids_clear(hdev);
825 goto unlock;
826 }
827
828 found = 0;
829
830 list_for_each_safe(p, n, &hdev->uuids) {
831 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
832
833 if (memcmp(match->uuid, cp->uuid, 16) != 0)
834 continue;
835
836 list_del(&match->list);
837 found++;
838 }
839
840 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200842 goto unlock;
843 }
844
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845 err = update_class(hdev);
846 if (err < 0)
847 goto unlock;
848
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300849 err = update_eir(hdev);
850 if (err < 0)
851 goto unlock;
852
Szymon Janc4e51eae2011-02-25 19:05:48 +0100853 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200854
855unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200857 hci_dev_put(hdev);
858
859 return err;
860}
861
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
863 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864{
865 struct hci_dev *hdev;
866 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867 int err;
868
869 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873 if (len != sizeof(*cp))
874 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200877 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
882 hdev->major_class = cp->major;
883 hdev->minor_class = cp->minor;
884
885 err = update_class(hdev);
886
887 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200891 hci_dev_put(hdev);
892
893 return err;
894}
895
Szymon Janc4e51eae2011-02-25 19:05:48 +0100896static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
897 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898{
899 struct hci_dev *hdev;
900 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200901 int err;
902
903 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100905 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +0100906 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100907
Szymon Janc4e51eae2011-02-25 19:05:48 +0100908 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200909 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200915
916 if (cp->enable) {
917 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
918 err = 0;
919 } else {
920 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
921 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300922 if (err == 0)
923 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200924 }
925
926 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
928 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200931 hci_dev_put(hdev);
932
933 return err;
934}
935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200937{
938 struct hci_dev *hdev;
939 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100940 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300941 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200942
943 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100944
945 if (len < sizeof(*cp))
946 return -EINVAL;
947
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200948 key_count = get_unaligned_le16(&cp->key_count);
949
950 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300951 if (expected_len > len) {
952 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
953 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200954 return -EINVAL;
955 }
956
Szymon Janc4e51eae2011-02-25 19:05:48 +0100957 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200958 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200960
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200962 key_count);
963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200965
966 hci_link_keys_clear(hdev);
967
968 set_bit(HCI_LINK_KEYS, &hdev->flags);
969
970 if (cp->debug_keys)
971 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
972 else
973 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
974
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300975 len -= sizeof(*cp);
976 i = 0;
977
978 while (i < len) {
979 struct mgmt_key_info *key = (void *) cp->keys + i;
980
Brian Gixa68668b2011-08-11 15:49:36 -0700981 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300984 struct key_master_id *id = (void *) key->data;
985
986 if (key->dlen != sizeof(struct key_master_id))
987 continue;
988
Vinicius Costa Gomes1fa2de32011-07-08 18:31:45 -0300989 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
Brian Gixa68668b2011-08-11 15:49:36 -0700990 key->auth, id->ediv, id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300991
992 continue;
993 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200996 key->pin_len);
997 }
998
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300999 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001002 hci_dev_put(hdev);
1003
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001004 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001005}
1006
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_remove_key *cp;
1011 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001012 int err;
1013
1014 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001015
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001016 if (len != sizeof(*cp))
1017 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1018
Szymon Janc4e51eae2011-02-25 19:05:48 +01001019 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001020 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001024
1025 err = hci_remove_link_key(hdev, &cp->bdaddr);
1026 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001028 goto unlock;
1029 }
1030
1031 err = 0;
1032
1033 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1034 goto unlock;
1035
1036 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1037 if (conn) {
1038 struct hci_cp_disconnect dc;
1039
1040 put_unaligned_le16(conn->handle, &dc.handle);
1041 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001043 }
1044
1045unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001047 hci_dev_put(hdev);
1048
1049 return err;
1050}
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001053{
1054 struct hci_dev *hdev;
1055 struct mgmt_cp_disconnect *cp;
1056 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001057 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059 int err;
1060
1061 BT_DBG("");
1062
1063 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001065 if (len != sizeof(*cp))
1066 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1067
Szymon Janc4e51eae2011-02-25 19:05:48 +01001068 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001073
1074 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001075 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001076 goto failed;
1077 }
1078
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1080 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001081 goto failed;
1082 }
1083
1084 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1085 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001086 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1087 if (!conn) {
1088 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1089 ENOTCONN);
1090 goto failed;
1091 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001092 }
1093
Szymon Janc4e51eae2011-02-25 19:05:48 +01001094 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001095 if (!cmd) {
1096 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001097 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001098 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001099
1100 put_unaligned_le16(conn->handle, &dc.handle);
1101 dc.reason = 0x13; /* Remote User Terminated Connection */
1102
1103 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1104 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001105 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001106
1107failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001109 hci_dev_put(hdev);
1110
1111 return err;
1112}
1113
Szymon Janc8ce62842011-03-01 16:55:32 +01001114static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001115{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001116 struct mgmt_rp_get_connections *rp;
1117 struct hci_dev *hdev;
1118 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001119 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001120 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001121 int i, err;
1122
1123 BT_DBG("");
1124
Szymon Janc4e51eae2011-02-25 19:05:48 +01001125 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001126 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001127 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001130
1131 count = 0;
1132 list_for_each(p, &hdev->conn_hash.list) {
1133 count++;
1134 }
1135
Johan Hedberga38528f2011-01-22 06:46:43 +02001136 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1137 rp = kmalloc(rp_len, GFP_ATOMIC);
1138 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001139 err = -ENOMEM;
1140 goto unlock;
1141 }
1142
Johan Hedberg2784eb42011-01-21 13:56:35 +02001143 put_unaligned_le16(count, &rp->conn_count);
1144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 read_lock(&hci_dev_list_lock);
1146
Johan Hedberg2784eb42011-01-21 13:56:35 +02001147 i = 0;
1148 list_for_each(p, &hdev->conn_hash.list) {
1149 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1150
1151 bacpy(&rp->conn[i++], &c->dst);
1152 }
1153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 read_unlock(&hci_dev_list_lock);
1155
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001157
1158unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001159 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001161 hci_dev_put(hdev);
1162 return err;
1163}
1164
Szymon Janc4e51eae2011-02-25 19:05:48 +01001165static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1166 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001167{
1168 struct hci_dev *hdev;
1169 struct mgmt_cp_pin_code_reply *cp;
1170 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001171 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001172 int err;
1173
1174 BT_DBG("");
1175
1176 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001178 if (len != sizeof(*cp))
1179 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1180
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186
1187 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001188 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189 goto failed;
1190 }
1191
Szymon Janc4e51eae2011-02-25 19:05:48 +01001192 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001193 if (!cmd) {
1194 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001196 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001197
1198 bacpy(&reply.bdaddr, &cp->bdaddr);
1199 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001201
1202 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1203 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001204 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205
1206failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001208 hci_dev_put(hdev);
1209
1210 return err;
1211}
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1214 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215{
1216 struct hci_dev *hdev;
1217 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219 int err;
1220
1221 BT_DBG("");
1222
1223 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001225 if (len != sizeof(*cp))
1226 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1227 EINVAL);
1228
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001231 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1232 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001235
1236 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1238 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001239 goto failed;
1240 }
1241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1243 data, len);
1244 if (!cmd) {
1245 err = -ENOMEM;
1246 goto failed;
1247 }
1248
1249 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1250 &cp->bdaddr);
1251 if (err < 0)
1252 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001253
1254failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001256 hci_dev_put(hdev);
1257
1258 return err;
1259}
1260
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1262 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001263{
1264 struct hci_dev *hdev;
1265 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001266
1267 BT_DBG("");
1268
1269 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001270
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001271 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001272 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001273
Szymon Janc4e51eae2011-02-25 19:05:48 +01001274 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001275 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001276 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001279
1280 hdev->io_capability = cp->io_capability;
1281
1282 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001283 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001286 hci_dev_put(hdev);
1287
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001289}
1290
Johan Hedberge9a416b2011-02-19 12:05:56 -03001291static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1292{
1293 struct hci_dev *hdev = conn->hdev;
1294 struct list_head *p;
1295
1296 list_for_each(p, &cmd_list) {
1297 struct pending_cmd *cmd;
1298
1299 cmd = list_entry(p, struct pending_cmd, list);
1300
1301 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1302 continue;
1303
1304 if (cmd->index != hdev->id)
1305 continue;
1306
1307 if (cmd->user_data != conn)
1308 continue;
1309
1310 return cmd;
1311 }
1312
1313 return NULL;
1314}
1315
1316static void pairing_complete(struct pending_cmd *cmd, u8 status)
1317{
1318 struct mgmt_rp_pair_device rp;
1319 struct hci_conn *conn = cmd->user_data;
1320
Brian Gixa68668b2011-08-11 15:49:36 -07001321 BT_DBG(" %u", status);
1322
Johan Hedberge9a416b2011-02-19 12:05:56 -03001323 bacpy(&rp.bdaddr, &conn->dst);
1324 rp.status = status;
1325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001327
1328 /* So we don't get further callbacks for this connection */
1329 conn->connect_cfm_cb = NULL;
1330 conn->security_cfm_cb = NULL;
1331 conn->disconn_cfm_cb = NULL;
1332
1333 hci_conn_put(conn);
1334
Johan Hedberga664b5b2011-02-19 12:06:02 -03001335 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336}
1337
1338static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1339{
1340 struct pending_cmd *cmd;
1341
Brian Gixa68668b2011-08-11 15:49:36 -07001342 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
1344 cmd = find_pairing(conn);
1345 if (!cmd) {
1346 BT_DBG("Unable to find a pending command");
1347 return;
1348 }
1349
1350 pairing_complete(cmd, status);
1351}
1352
Brian Gixa68668b2011-08-11 15:49:36 -07001353static void security_complete_cb(struct hci_conn *conn, u8 status)
1354{
1355 struct pending_cmd *cmd;
1356
1357 BT_DBG(" %u", status);
1358
1359 cmd = find_pairing(conn);
1360 if (!cmd) {
1361 BT_DBG("Unable to find a pending command");
1362 return;
1363 }
1364
1365 if (conn->type == LE_LINK)
1366 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1367 status ? 0 : 1);
1368 else
1369 pairing_complete(cmd, status);
1370}
1371
1372static void connect_complete_cb(struct hci_conn *conn, u8 status)
1373{
1374 struct pending_cmd *cmd;
1375
1376 BT_DBG("conn: %p %u", conn, status);
1377
1378 cmd = find_pairing(conn);
1379 if (!cmd) {
1380 BT_DBG("Unable to find a pending command");
1381 return;
1382 }
Brian Gixa68668b2011-08-11 15:49:36 -07001383}
1384
1385static void discovery_terminated(struct pending_cmd *cmd, void *data)
1386{
1387 struct mgmt_mode ev = {0};
1388 struct disco_interleave *ilp = cmd->param;
1389
1390 BT_DBG("");
1391 del_timer_sync(&ilp->le_timer);
1392 del_timer_sync(&ilp->timer);
1393 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1394
1395 list_del(&cmd->list);
1396
1397 mgmt_pending_free(cmd);
1398}
1399
Szymon Janc4e51eae2011-02-25 19:05:48 +01001400static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001401{
1402 struct hci_dev *hdev;
1403 struct mgmt_cp_pair_device *cp;
1404 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001405 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001406 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001407 int err;
1408
1409 BT_DBG("");
1410
Brian Gix64bd5302011-09-08 11:35:48 -07001411 cp = (void *) data;
1412
1413 if (len != sizeof(*cp))
1414 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1415
Szymon Janc4e51eae2011-02-25 19:05:48 +01001416 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001417
Johan Hedberge9a416b2011-02-19 12:05:56 -03001418 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001422
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301423 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1424 io_cap = cp->io_cap;
1425 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001426 sec_level = BT_SECURITY_MEDIUM;
1427 auth_type = HCI_AT_DEDICATED_BONDING;
1428 } else {
1429 sec_level = BT_SECURITY_HIGH;
1430 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1431 }
1432
Brian Gixa68668b2011-08-11 15:49:36 -07001433 if (hci_find_adv_entry(hdev, &cp->bdaddr)) {
1434 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1435 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001436 } else {
1437 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1438 if (io_cap == 0x04)
1439 io_cap = 0x01;
1440 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1441 auth_type);
1442 }
1443
Ville Tervo30e76272011-02-22 16:10:53 -03001444 if (IS_ERR(conn)) {
1445 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446 goto unlock;
1447 }
1448
1449 if (conn->connect_cfm_cb) {
1450 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001452 goto unlock;
1453 }
1454
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001456 if (!cmd) {
1457 err = -ENOMEM;
1458 hci_conn_put(conn);
1459 goto unlock;
1460 }
1461
Brian Gixa68668b2011-08-11 15:49:36 -07001462 conn->connect_cfm_cb = connect_complete_cb;
1463 conn->security_cfm_cb = security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001464 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001465 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001466 cmd->user_data = conn;
1467
1468 if (conn->state == BT_CONNECTED &&
1469 hci_conn_security(conn, sec_level, auth_type))
1470 pairing_complete(cmd, 0);
1471
1472 err = 0;
1473
1474unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001476 hci_dev_put(hdev);
1477
1478 return err;
1479}
1480
Szymon Janc4e51eae2011-02-25 19:05:48 +01001481static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001482 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001483{
1484 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001485 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001486 struct pending_cmd *cmd;
1487 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001488 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001489 int err;
1490
Brian Gixa68668b2011-08-11 15:49:36 -07001491 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001492
Brian Gixa68668b2011-08-11 15:49:36 -07001493 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001494 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001495 else
1496 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001497
Brian Gixa68668b2011-08-11 15:49:36 -07001498 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001499 return cmd_status(sk, index, mgmt_op, EINVAL);
1500
Szymon Janc4e51eae2011-02-25 19:05:48 +01001501 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001502 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001503 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001506
Johan Hedberga5c29682011-02-19 12:05:57 -03001507 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001509 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001510 }
1511
Brian Gixa68668b2011-08-11 15:49:36 -07001512 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1513 if (le_conn) {
1514 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1515 goto done;
1516 }
1517 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1518 "Reject" : "Accept");
1519
Szymon Janc4e51eae2011-02-25 19:05:48 +01001520 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001521 if (!cmd) {
1522 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001523 goto done;
1524 }
1525
1526 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1527 if (err < 0)
1528 mgmt_pending_remove(cmd);
1529
1530done:
1531 hci_dev_unlock(hdev);
1532 hci_dev_put(hdev);
1533
1534 return err;
1535}
1536
1537static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1538 u16 len)
1539{
1540 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1541 struct hci_cp_remote_name_req hci_cp;
1542 struct hci_dev *hdev;
1543 struct pending_cmd *cmd;
1544 int err;
1545
1546 BT_DBG("");
1547
1548 if (len != sizeof(*mgmt_cp))
1549 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1550
1551 hdev = hci_dev_get(index);
1552 if (!hdev)
1553 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1554
1555 hci_dev_lock(hdev);
1556
1557 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1558 if (!cmd) {
1559 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001560 goto failed;
1561 }
1562
Brian Gixa68668b2011-08-11 15:49:36 -07001563 memset(&hci_cp, 0, sizeof(hci_cp));
1564 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1565 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1566 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001567 if (err < 0)
1568 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001569
1570failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001572 hci_dev_put(hdev);
1573
1574 return err;
1575}
1576
Johan Hedbergb312b1612011-03-16 14:29:37 +02001577static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1578 u16 len)
1579{
1580 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1581 struct hci_cp_write_local_name hci_cp;
1582 struct hci_dev *hdev;
1583 struct pending_cmd *cmd;
1584 int err;
1585
1586 BT_DBG("");
1587
1588 if (len != sizeof(*mgmt_cp))
1589 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1590
1591 hdev = hci_dev_get(index);
1592 if (!hdev)
1593 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001596
1597 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1598 if (!cmd) {
1599 err = -ENOMEM;
1600 goto failed;
1601 }
1602
1603 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1604 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1605 &hci_cp);
1606 if (err < 0)
1607 mgmt_pending_remove(cmd);
1608
1609failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001611 hci_dev_put(hdev);
1612
1613 return err;
1614}
1615
Brian Gixa68668b2011-08-11 15:49:36 -07001616static void discovery_rsp(struct pending_cmd *cmd, void *data)
1617{
1618 struct mgmt_mode ev;
1619
1620 BT_DBG("");
1621 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1622 ev.val = 1;
1623 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1624 } else {
1625 ev.val = 0;
1626 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1627 NULL, 0);
1628 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1629 struct disco_interleave *ilp = cmd->param;
1630
1631 del_timer_sync(&ilp->le_timer);
1632 del_timer_sync(&ilp->timer);
1633 }
1634 }
1635
1636 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1637
1638 list_del(&cmd->list);
1639
1640 mgmt_pending_free(cmd);
1641}
1642
1643void mgmt_inquiry_started(u16 index)
1644{
1645 BT_DBG("");
1646 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1647 discovery_rsp, NULL);
1648}
1649
1650void mgmt_inquiry_complete_evt(u16 index, u8 status)
1651{
1652 struct hci_dev *hdev;
1653 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1654 struct pending_cmd *cmd;
1655 int err = -1;
1656
1657 BT_DBG("");
1658
1659 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001660
1661 if (hdev)
1662 hci_dev_lock(hdev);
1663
Brian Gixa68668b2011-08-11 15:49:36 -07001664 if (!hdev || !lmp_le_capable(hdev)) {
1665 struct mgmt_mode cp = {0};
1666
1667 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1668 discovery_terminated, NULL);
1669
1670 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001671
Brian Gix64bd5302011-09-08 11:35:48 -07001672 if (hdev)
1673 goto done;
1674 else
1675 return;
1676 }
Brian Gixa68668b2011-08-11 15:49:36 -07001677
1678 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1679 if (cmd && cmd->param) {
1680 struct disco_interleave *ilp = cmd->param;
1681
1682 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1683 sizeof(le_cp), &le_cp);
1684 if (err >= 0) {
1685 mod_timer(&ilp->le_timer, jiffies +
1686 msecs_to_jiffies(ilp->int_phase * 1000));
1687 ilp->mode = SCAN_LE;
1688 } else
1689 ilp->mode = SCAN_IDLE;
1690 }
1691
1692 if (err < 0)
1693 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1694 discovery_terminated, NULL);
1695
Brian Gix64bd5302011-09-08 11:35:48 -07001696done:
Brian Gixa68668b2011-08-11 15:49:36 -07001697 hci_dev_unlock(hdev);
1698 hci_dev_put(hdev);
1699}
1700
1701static void disco_to(unsigned long data)
1702{
1703 struct disco_interleave *ilp = (void *)data;
1704 struct hci_dev *hdev;
1705 struct pending_cmd *cmd;
1706
1707 BT_DBG("hci%d", ilp->index);
1708
1709 del_timer_sync(&ilp->le_timer);
1710 hdev = hci_dev_get(ilp->index);
1711
1712 if (hdev) {
1713 hci_dev_lock(hdev);
1714
1715 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1716
1717 if (ilp->mode != SCAN_IDLE) {
1718 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1719
1720 if (ilp->mode == SCAN_LE)
1721 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1722 sizeof(le_cp), &le_cp);
1723 else
1724 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1725 0, NULL);
1726
1727 ilp->mode = SCAN_IDLE;
1728 }
1729
1730 if (cmd) {
1731 struct mgmt_mode cp = {0};
1732
1733 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1734 sizeof(cp), NULL);
1735 mgmt_pending_remove(cmd);
1736 }
1737
1738 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001739 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001740 }
1741}
1742
1743static void disco_le_to(unsigned long data)
1744{
1745 struct disco_interleave *ilp = (void *)data;
1746 struct hci_dev *hdev;
1747 struct pending_cmd *cmd;
1748 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1749
1750 BT_DBG("hci%d", ilp->index);
1751
1752 hdev = hci_dev_get(ilp->index);
1753 del_timer_sync(&ilp->le_timer);
1754
1755 if (hdev) {
1756 hci_dev_lock(hdev);
1757
1758 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1759
1760 if (ilp->mode == SCAN_LE)
1761 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1762 sizeof(le_cp), &le_cp);
1763
1764 /* re-start BR scan */
1765 if (cmd) {
1766 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1767 ilp->int_phase *= 2;
1768 ilp->int_count = 0;
1769 cp.num_rsp = (u8) ilp->int_phase;
1770 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1771 ilp->mode = SCAN_BR;
1772 } else
1773 ilp->mode = SCAN_IDLE;
1774
1775 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001776 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001777 }
1778}
1779
1780static int start_discovery(struct sock *sk, u16 index)
1781{
1782 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1783 struct hci_dev *hdev;
1784 struct pending_cmd *cmd;
1785 int err;
1786
1787 BT_DBG("");
1788
1789 hdev = hci_dev_get(index);
1790 if (!hdev)
1791 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1792
1793 hci_dev_lock(hdev);
1794
1795 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1796 if (!cmd) {
1797 err = -ENOMEM;
1798 goto failed;
1799 }
1800
1801 /* If LE Capable, we will alternate between BR/EDR and LE */
1802 if (lmp_le_capable(hdev)) {
1803 struct hci_cp_le_set_scan_parameters le_cp;
1804
1805 /* Shorten BR scan params */
1806 cp.num_rsp = 1;
1807 cp.length /= 2;
1808
1809 /* Setup LE scan params */
1810 memset(&le_cp, 0, sizeof(le_cp));
1811 le_cp.type = 0x01; /* Active scanning */
1812 /* The recommended value for scan interval and window is
1813 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1814 le_cp.interval = cpu_to_le16(0x0012);
1815 le_cp.window = cpu_to_le16(0x0012);
1816 le_cp.own_bdaddr_type = 0; /* Public address */
1817 le_cp.filter = 0; /* Accept all adv packets */
1818
1819 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1820 sizeof(le_cp), &le_cp);
1821 }
1822
1823 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1824
1825 if (err < 0)
1826 mgmt_pending_remove(cmd);
1827 else if (lmp_le_capable(hdev)) {
1828 struct disco_interleave il, *ilp;
1829
1830 il.int_phase = 1;
1831 il.int_count = 0;
1832 il.index = index;
1833 il.mode = SCAN_BR;
1834 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1835 sizeof(struct disco_interleave));
1836 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1837 if (cmd) {
1838 ilp = cmd->param;
1839 setup_timer(&ilp->le_timer, disco_le_to,
1840 (unsigned long) ilp);
1841 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1842 mod_timer(&ilp->timer,
1843 jiffies + msecs_to_jiffies(20000));
1844 }
1845 }
1846
1847failed:
1848 hci_dev_unlock(hdev);
1849 hci_dev_put(hdev);
1850
1851 return err;
1852}
1853
1854static int stop_discovery(struct sock *sk, u16 index)
1855{
1856 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1857 struct mgmt_mode mode_cp = {0};
1858 struct disco_interleave *ilp = NULL;
1859 struct hci_dev *hdev;
1860 struct pending_cmd *cmd = NULL;
1861 int err = -EPERM;
1862
1863 BT_DBG("");
1864
1865 hdev = hci_dev_get(index);
1866 if (!hdev)
1867 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1868
1869 hci_dev_lock(hdev);
1870
1871 if (lmp_le_capable(hdev)) {
1872 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1873 if (!cmd) {
1874 err = -ENOMEM;
1875 goto failed;
1876 }
1877
1878 ilp = cmd->param;
1879 }
1880
1881 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1882 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1883 sizeof(le_cp), &le_cp);
1884
1885 if (err < 0) {
1886 if (!ilp || (ilp->mode == SCAN_BR))
1887 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1888 0, NULL);
1889 }
1890
1891 if (ilp) {
1892 ilp->mode = SCAN_IDLE;
1893 del_timer_sync(&ilp->le_timer);
1894 del_timer_sync(&ilp->timer);
1895 }
1896
1897 if (err < 0 && cmd)
1898 mgmt_pending_remove(cmd);
1899
1900 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1901
1902failed:
1903 hci_dev_unlock(hdev);
1904 hci_dev_put(hdev);
1905
1906 if (err < 0)
1907 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1908 else
1909 return err;
1910}
1911
Szymon Jancc35938b2011-03-22 13:12:21 +01001912static int read_local_oob_data(struct sock *sk, u16 index)
1913{
1914 struct hci_dev *hdev;
1915 struct pending_cmd *cmd;
1916 int err;
1917
1918 BT_DBG("hci%u", index);
1919
1920 hdev = hci_dev_get(index);
1921 if (!hdev)
1922 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1923 ENODEV);
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001926
1927 if (!test_bit(HCI_UP, &hdev->flags)) {
1928 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1929 ENETDOWN);
1930 goto unlock;
1931 }
1932
1933 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1934 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1935 EOPNOTSUPP);
1936 goto unlock;
1937 }
1938
1939 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1940 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1941 goto unlock;
1942 }
1943
1944 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1945 if (!cmd) {
1946 err = -ENOMEM;
1947 goto unlock;
1948 }
1949
1950 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1951 if (err < 0)
1952 mgmt_pending_remove(cmd);
1953
1954unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001956 hci_dev_put(hdev);
1957
1958 return err;
1959}
1960
Szymon Janc2763eda2011-03-22 13:12:22 +01001961static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1962 u16 len)
1963{
1964 struct hci_dev *hdev;
1965 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1966 int err;
1967
1968 BT_DBG("hci%u ", index);
1969
1970 if (len != sizeof(*cp))
1971 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1972 EINVAL);
1973
1974 hdev = hci_dev_get(index);
1975 if (!hdev)
1976 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1977 ENODEV);
1978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001980
1981 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1982 cp->randomizer);
1983 if (err < 0)
1984 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1985 else
1986 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1987 0);
1988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001990 hci_dev_put(hdev);
1991
1992 return err;
1993}
1994
1995static int remove_remote_oob_data(struct sock *sk, u16 index,
1996 unsigned char *data, u16 len)
1997{
1998 struct hci_dev *hdev;
1999 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2000 int err;
2001
2002 BT_DBG("hci%u ", index);
2003
2004 if (len != sizeof(*cp))
2005 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2006 EINVAL);
2007
2008 hdev = hci_dev_get(index);
2009 if (!hdev)
2010 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2011 ENODEV);
2012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002014
2015 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2016 if (err < 0)
2017 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2018 -err);
2019 else
2020 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2021 NULL, 0);
2022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002024 hci_dev_put(hdev);
2025
2026 return err;
2027}
2028
Johan Hedberg03811012010-12-08 00:21:06 +02002029int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2030{
2031 unsigned char *buf;
2032 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002033 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002034 int err;
2035
2036 BT_DBG("got %zu bytes", msglen);
2037
2038 if (msglen < sizeof(*hdr))
2039 return -EINVAL;
2040
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002041 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002042 if (!buf)
2043 return -ENOMEM;
2044
2045 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2046 err = -EFAULT;
2047 goto done;
2048 }
2049
2050 hdr = (struct mgmt_hdr *) buf;
2051 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002052 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002053 len = get_unaligned_le16(&hdr->len);
2054
2055 if (len != msglen - sizeof(*hdr)) {
2056 err = -EINVAL;
2057 goto done;
2058 }
2059
Brian Gixa68668b2011-08-11 15:49:36 -07002060 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002061 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002062 case MGMT_OP_READ_VERSION:
2063 err = read_version(sk);
2064 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002065 case MGMT_OP_READ_INDEX_LIST:
2066 err = read_index_list(sk);
2067 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002068 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002069 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002070 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002071 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002072 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002073 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002074 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002075 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002076 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002077 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002078 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002079 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002080 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002081 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002082 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002083 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002084 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085 break;
2086 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002087 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002089 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002090 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002091 break;
2092 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002093 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002094 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002095 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002096 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002097 break;
2098 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002099 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002100 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002101 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002103 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002104 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002105 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002106 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002107 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002108 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002109 break;
2110 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002111 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002112 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002113 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002114 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002115 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002116 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002118 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002119 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002120 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002121 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002122 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2123 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002124 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002125 case MGMT_OP_SET_LOCAL_NAME:
2126 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2127 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002128 case MGMT_OP_START_DISCOVERY:
2129 err = start_discovery(sk, index);
2130 break;
2131 case MGMT_OP_STOP_DISCOVERY:
2132 err = stop_discovery(sk, index);
2133 break;
2134 case MGMT_OP_RESOLVE_NAME:
2135 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2136 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002137 case MGMT_OP_READ_LOCAL_OOB_DATA:
2138 err = read_local_oob_data(sk, index);
2139 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002140 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2141 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2142 break;
2143 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2144 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2145 len);
2146 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147
Johan Hedberg03811012010-12-08 00:21:06 +02002148 default:
2149 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002151 break;
2152 }
2153
Johan Hedberge41d8b42010-12-13 21:07:03 +02002154 if (err < 0)
2155 goto done;
2156
Johan Hedberg03811012010-12-08 00:21:06 +02002157 err = msglen;
2158
2159done:
2160 kfree(buf);
2161 return err;
2162}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002163
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002164int mgmt_index_added(u16 index)
2165{
Brian Gixa68668b2011-08-11 15:49:36 -07002166 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002167 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002168}
2169
2170int mgmt_index_removed(u16 index)
2171{
Brian Gixa68668b2011-08-11 15:49:36 -07002172 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002173 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002174}
2175
Johan Hedberg73f22f62010-12-29 16:00:25 +02002176struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002177 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002178 struct sock *sk;
2179};
2180
Johan Hedberg72a734e2010-12-30 00:38:22 +02002181static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002182{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002183 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002184 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002185
Johan Hedberg72a734e2010-12-30 00:38:22 +02002186 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002187 return;
2188
Johan Hedberg053f0212011-01-26 13:07:10 +02002189 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002190
2191 list_del(&cmd->list);
2192
2193 if (match->sk == NULL) {
2194 match->sk = cmd->sk;
2195 sock_hold(match->sk);
2196 }
2197
2198 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002199}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002200
2201int mgmt_powered(u16 index, u8 powered)
2202{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002203 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002204 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002205 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002206
Brian Gixa68668b2011-08-11 15:49:36 -07002207 BT_DBG("hci%u %d", index, powered);
2208
Johan Hedberg72a734e2010-12-30 00:38:22 +02002209 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002210
Johan Hedberg72a734e2010-12-30 00:38:22 +02002211 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002212
Szymon Janc4e51eae2011-02-25 19:05:48 +01002213 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002214
2215 if (match.sk)
2216 sock_put(match.sk);
2217
2218 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002219}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002220
Johan Hedberg73f22f62010-12-29 16:00:25 +02002221int mgmt_discoverable(u16 index, u8 discoverable)
2222{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002223 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002224 struct cmd_lookup match = { discoverable, NULL };
2225 int ret;
2226
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002227 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002228
Johan Hedberg72a734e2010-12-30 00:38:22 +02002229 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002230
Szymon Janc4e51eae2011-02-25 19:05:48 +01002231 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2232 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002233
2234 if (match.sk)
2235 sock_put(match.sk);
2236
2237 return ret;
2238}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002239
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002240int mgmt_connectable(u16 index, u8 connectable)
2241{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002242 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002243 struct cmd_lookup match = { connectable, NULL };
2244 int ret;
2245
Johan Hedberg72a734e2010-12-30 00:38:22 +02002246 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002247
Johan Hedberg72a734e2010-12-30 00:38:22 +02002248 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002249
Szymon Janc4e51eae2011-02-25 19:05:48 +01002250 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002251
2252 if (match.sk)
2253 sock_put(match.sk);
2254
2255 return ret;
2256}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002257
Brian Gixa68668b2011-08-11 15:49:36 -07002258int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002259{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002260 struct mgmt_ev_new_key *ev;
2261 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002262
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002263 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2264 ev = kzalloc(total, GFP_ATOMIC);
2265 if (!ev)
2266 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002267
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002268 bacpy(&ev->key.bdaddr, &key->bdaddr);
2269 ev->key.type = key->type;
2270 memcpy(ev->key.val, key->val, 16);
2271 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002272 ev->key.auth = key->auth;
2273 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002274 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002275
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002276 memcpy(ev->key.data, key->data, key->dlen);
2277
2278 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2279
2280 kfree(ev);
2281
2282 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002283}
Johan Hedbergf7520542011-01-20 12:34:39 +02002284
2285int mgmt_connected(u16 index, bdaddr_t *bdaddr)
2286{
2287 struct mgmt_ev_connected ev;
2288
Johan Hedbergf7520542011-01-20 12:34:39 +02002289 bacpy(&ev.bdaddr, bdaddr);
2290
Szymon Janc4e51eae2011-02-25 19:05:48 +01002291 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002292}
2293
Johan Hedberg8962ee72011-01-20 12:40:27 +02002294static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2295{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002296 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002297 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002298 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002299
Johan Hedberga38528f2011-01-22 06:46:43 +02002300 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002301
Szymon Janc4e51eae2011-02-25 19:05:48 +01002302 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002303
2304 *sk = cmd->sk;
2305 sock_hold(*sk);
2306
Johan Hedberga664b5b2011-02-19 12:06:02 -03002307 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002308}
2309
Johan Hedbergf7520542011-01-20 12:34:39 +02002310int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2311{
2312 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002313 struct sock *sk = NULL;
2314 int err;
2315
2316 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002317
Johan Hedbergf7520542011-01-20 12:34:39 +02002318 bacpy(&ev.bdaddr, bdaddr);
2319
Szymon Janc4e51eae2011-02-25 19:05:48 +01002320 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002321
2322 if (sk)
2323 sock_put(sk);
2324
2325 return err;
2326}
2327
2328int mgmt_disconnect_failed(u16 index)
2329{
2330 struct pending_cmd *cmd;
2331 int err;
2332
2333 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2334 if (!cmd)
2335 return -ENOENT;
2336
Szymon Janc4e51eae2011-02-25 19:05:48 +01002337 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002338
Johan Hedberga664b5b2011-02-19 12:06:02 -03002339 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002340
2341 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002342}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002343
2344int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2345{
2346 struct mgmt_ev_connect_failed ev;
2347
Johan Hedberg17d5c042011-01-22 06:09:08 +02002348 bacpy(&ev.bdaddr, bdaddr);
2349 ev.status = status;
2350
Szymon Janc4e51eae2011-02-25 19:05:48 +01002351 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002352}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002355{
2356 struct mgmt_ev_pin_code_request ev;
2357
Brian Gixa68668b2011-08-11 15:49:36 -07002358 BT_DBG("hci%u", index);
2359
Johan Hedberg980e1a52011-01-22 06:10:07 +02002360 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002361 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002362
Szymon Janc4e51eae2011-02-25 19:05:48 +01002363 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2364 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002365}
2366
2367int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2368{
2369 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002370 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002371 int err;
2372
2373 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2374 if (!cmd)
2375 return -ENOENT;
2376
Johan Hedbergac56fb12011-02-19 12:05:59 -03002377 bacpy(&rp.bdaddr, bdaddr);
2378 rp.status = status;
2379
Szymon Janc4e51eae2011-02-25 19:05:48 +01002380 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2381 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002382
Johan Hedberga664b5b2011-02-19 12:06:02 -03002383 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002384
2385 return err;
2386}
2387
2388int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2389{
2390 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002391 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002392 int err;
2393
2394 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2395 if (!cmd)
2396 return -ENOENT;
2397
Johan Hedbergac56fb12011-02-19 12:05:59 -03002398 bacpy(&rp.bdaddr, bdaddr);
2399 rp.status = status;
2400
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2402 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002403
Johan Hedberga664b5b2011-02-19 12:06:02 -03002404 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002405
2406 return err;
2407}
Johan Hedberga5c29682011-02-19 12:05:57 -03002408
Brian Gixa68668b2011-08-11 15:49:36 -07002409int mgmt_user_confirm_request(u16 index, u8 event,
2410 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002411{
2412 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002413 struct hci_conn *conn = NULL;
2414 struct hci_dev *hdev;
2415 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2416
2417 BT_DBG("hci%u", index);
2418
2419 hdev = hci_dev_get(index);
2420
Brian Gix64bd5302011-09-08 11:35:48 -07002421 if (!hdev)
2422 return -ENODEV;
2423
2424 hci_dev_lock(hdev);
2425
2426 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002427
2428 ev.auto_confirm = 0;
2429
2430 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2431 goto no_auto_confirm;
2432
2433 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2434 rem_cap = conn->remote_cap;
2435 loc_mitm = conn->auth_type & 0x01;
2436 rem_mitm = conn->remote_auth & 0x01;
2437
2438 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2439 goto no_auto_confirm;
2440
2441
2442 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2443 ev.auto_confirm = 1;
2444
2445no_auto_confirm:
2446 bacpy(&ev.bdaddr, bdaddr);
2447 ev.event = event;
2448 put_unaligned_le32(value, &ev.value);
2449
Brian Gix64bd5302011-09-08 11:35:48 -07002450 hci_dev_unlock(hdev);
2451 hci_dev_put(hdev);
2452
Brian Gixa68668b2011-08-11 15:49:36 -07002453 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2454 NULL);
2455}
2456
2457int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2458{
2459 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002460
2461 BT_DBG("hci%u", index);
2462
Johan Hedberga5c29682011-02-19 12:05:57 -03002463 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002464
Brian Gixa68668b2011-08-11 15:49:36 -07002465 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002466 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002467}
2468
2469static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2470 u8 opcode)
2471{
2472 struct pending_cmd *cmd;
2473 struct mgmt_rp_user_confirm_reply rp;
2474 int err;
2475
2476 cmd = mgmt_pending_find(opcode, index);
2477 if (!cmd)
2478 return -ENOENT;
2479
Johan Hedberga5c29682011-02-19 12:05:57 -03002480 bacpy(&rp.bdaddr, bdaddr);
2481 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002482 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002483
Johan Hedberga664b5b2011-02-19 12:06:02 -03002484 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002485
2486 return err;
2487}
2488
2489int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2490{
2491 return confirm_reply_complete(index, bdaddr, status,
2492 MGMT_OP_USER_CONFIRM_REPLY);
2493}
2494
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002495int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002496{
2497 return confirm_reply_complete(index, bdaddr, status,
2498 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2499}
Johan Hedberg2a611692011-02-19 12:06:00 -03002500
2501int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2502{
2503 struct mgmt_ev_auth_failed ev;
2504
Johan Hedberg2a611692011-02-19 12:06:00 -03002505 bacpy(&ev.bdaddr, bdaddr);
2506 ev.status = status;
2507
Szymon Janc4e51eae2011-02-25 19:05:48 +01002508 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002509}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002510
2511int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2512{
2513 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002514 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002515 struct mgmt_cp_set_local_name ev;
2516 int err;
2517
2518 memset(&ev, 0, sizeof(ev));
2519 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2520
2521 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2522 if (!cmd)
2523 goto send_event;
2524
2525 if (status) {
2526 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2527 goto failed;
2528 }
2529
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002530 hdev = hci_dev_get(index);
2531 if (hdev) {
2532 hci_dev_lock_bh(hdev);
2533 update_eir(hdev);
2534 hci_dev_unlock_bh(hdev);
2535 hci_dev_put(hdev);
2536 }
2537
Johan Hedbergb312b1612011-03-16 14:29:37 +02002538 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2539 sizeof(ev));
2540 if (err < 0)
2541 goto failed;
2542
2543send_event:
2544 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2545 cmd ? cmd->sk : NULL);
2546
2547failed:
2548 if (cmd)
2549 mgmt_pending_remove(cmd);
2550 return err;
2551}
Szymon Jancc35938b2011-03-22 13:12:21 +01002552
2553int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2554 u8 status)
2555{
2556 struct pending_cmd *cmd;
2557 int err;
2558
2559 BT_DBG("hci%u status %u", index, status);
2560
2561 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2562 if (!cmd)
2563 return -ENOENT;
2564
2565 if (status) {
2566 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2567 EIO);
2568 } else {
2569 struct mgmt_rp_read_local_oob_data rp;
2570
2571 memcpy(rp.hash, hash, sizeof(rp.hash));
2572 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2573
2574 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2575 &rp, sizeof(rp));
2576 }
2577
2578 mgmt_pending_remove(cmd);
2579
2580 return err;
2581}
Johan Hedberge17acd42011-03-30 23:57:16 +03002582
Brian Gixa68668b2011-08-11 15:49:36 -07002583int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2584 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002585{
2586 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002587 struct pending_cmd *cmd;
2588 int err;
2589
2590 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002591
2592 memset(&ev, 0, sizeof(ev));
2593
2594 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002595 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002596 ev.type = type;
2597 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002598
Brian Gixa68668b2011-08-11 15:49:36 -07002599 if (dev_class)
2600 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002601
Brian Gixa68668b2011-08-11 15:49:36 -07002602 if (eir && eir_len)
2603 memcpy(ev.eir, eir, eir_len);
2604
2605 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2606
2607 if (err < 0)
2608 return err;
2609
2610 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2611 if (cmd) {
2612 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002613 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002614
2615 ilp->int_count++;
2616 if (hdev && ilp->int_count >= ilp->int_phase) {
2617 /* Inquiry scan for General Discovery LAP */
2618 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2619 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002620
2621 hci_dev_lock(hdev);
2622
Brian Gixa68668b2011-08-11 15:49:36 -07002623 ilp->int_phase *= 2;
2624 ilp->int_count = 0;
2625 if (ilp->mode == SCAN_LE) {
2626 /* cancel LE scan */
2627 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2628 sizeof(le_cp), &le_cp);
2629 /* start BR scan */
2630 cp.num_rsp = (u8) ilp->int_phase;
2631 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2632 sizeof(cp), &cp);
2633 ilp->mode = SCAN_BR;
2634 del_timer_sync(&ilp->le_timer);
2635 }
Brian Gix64bd5302011-09-08 11:35:48 -07002636 hci_dev_unlock(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002637 }
Brian Gix64bd5302011-09-08 11:35:48 -07002638
2639 if (hdev)
2640 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002641 }
2642
2643 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002644}
Johan Hedberga88a9652011-03-30 13:18:12 +03002645
Brian Gixa68668b2011-08-11 15:49:36 -07002646
2647int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002648{
2649 struct mgmt_ev_remote_name ev;
2650
2651 memset(&ev, 0, sizeof(ev));
2652
2653 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002654 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002655 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2656
2657 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2658}