blob: 6ec00d524f6cd8cae5900e8f665486bfd96e5a15 [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) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700149 struct hci_dev *d = list_entry(p, struct hci_dev, list);
150 if (d->dev_type != HCI_BREDR)
151 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200152 count++;
153 }
154
Johan Hedberga38528f2011-01-22 06:46:43 +0200155 rp_len = sizeof(*rp) + (2 * count);
156 rp = kmalloc(rp_len, GFP_ATOMIC);
157 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100158 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200159 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100160 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200161
Brian Gixa68668b2011-08-11 15:49:36 -0700162 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200163
164 i = 0;
165 list_for_each(p, &hci_dev_list) {
166 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200167
168 hci_del_off_timer(d);
169
Peter Krystad1fc44072011-08-30 15:38:12 -0700170 if (d->dev_type != HCI_BREDR)
171 continue;
172
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200173 set_bit(HCI_MGMT, &d->flags);
174
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200175 if (test_bit(HCI_SETUP, &d->flags))
176 continue;
177
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200178 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700179 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200180 BT_DBG("Added hci%u", d->id);
181 }
182
183 read_unlock(&hci_dev_list_lock);
184
Szymon Janc4e51eae2011-02-25 19:05:48 +0100185 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
186 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 kfree(rp);
189
190 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200191}
192
Szymon Janc4e51eae2011-02-25 19:05:48 +0100193static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200194{
Johan Hedberga38528f2011-01-22 06:46:43 +0200195 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200196 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200199
Szymon Janc4e51eae2011-02-25 19:05:48 +0100200 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100202 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200203
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200204 hci_del_off_timer(hdev);
205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200208 set_bit(HCI_MGMT, &hdev->flags);
209
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200210 memset(&rp, 0, sizeof(rp));
211
Johan Hedberga38528f2011-01-22 06:46:43 +0200212 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp.powered = test_bit(HCI_UP, &hdev->flags);
215 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
216 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
217 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218
219 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200220 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200222 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200224 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200225
Johan Hedberga38528f2011-01-22 06:46:43 +0200226 bacpy(&rp.bdaddr, &hdev->bdaddr);
227 memcpy(rp.features, hdev->features, 8);
228 memcpy(rp.dev_class, hdev->dev_class, 3);
229 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
230 rp.hci_ver = hdev->hci_ver;
231 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200233 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200236 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200237
Szymon Janc4e51eae2011-02-25 19:05:48 +0100238 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200239}
240
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241static void mgmt_pending_free(struct pending_cmd *cmd)
242{
Brian Gixa68668b2011-08-11 15:49:36 -0700243 BT_DBG("%d", cmd->opcode);
244
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200245 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100246 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200247 kfree(cmd);
248}
249
Johan Hedberg366a0332011-02-19 12:05:55 -0300250static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
251 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200252{
253 struct pending_cmd *cmd;
254
Brian Gixa68668b2011-08-11 15:49:36 -0700255 BT_DBG("%d", opcode);
256
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200257 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
258 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300259 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200260
261 cmd->opcode = opcode;
262 cmd->index = index;
263
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100264 cmd->param = kmalloc(len, GFP_ATOMIC);
265 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200266 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300267 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200268 }
269
Szymon Janc8fce6352011-03-22 13:12:20 +0100270 if (data)
271 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200272
273 cmd->sk = sk;
274 sock_hold(sk);
275
276 list_add(&cmd->list, &cmd_list);
277
Johan Hedberg366a0332011-02-19 12:05:55 -0300278 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200279}
280
281static void mgmt_pending_foreach(u16 opcode, int index,
282 void (*cb)(struct pending_cmd *cmd, void *data),
283 void *data)
284{
285 struct list_head *p, *n;
286
Brian Gixa68668b2011-08-11 15:49:36 -0700287 BT_DBG(" %d", opcode);
288
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200289 list_for_each_safe(p, n, &cmd_list) {
290 struct pending_cmd *cmd;
291
292 cmd = list_entry(p, struct pending_cmd, list);
293
294 if (cmd->opcode != opcode)
295 continue;
296
297 if (index >= 0 && cmd->index != index)
298 continue;
299
300 cb(cmd, data);
301 }
302}
303
304static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
305{
306 struct list_head *p;
307
Brian Gixa68668b2011-08-11 15:49:36 -0700308 BT_DBG(" %d", opcode);
309
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310 list_for_each(p, &cmd_list) {
311 struct pending_cmd *cmd;
312
313 cmd = list_entry(p, struct pending_cmd, list);
314
315 if (cmd->opcode != opcode)
316 continue;
317
318 if (index >= 0 && cmd->index != index)
319 continue;
320
321 return cmd;
322 }
323
324 return NULL;
325}
326
Johan Hedberga664b5b2011-02-19 12:06:02 -0300327static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200328{
Brian Gixa68668b2011-08-11 15:49:36 -0700329 BT_DBG(" %d", cmd->opcode);
330
Johan Hedberg73f22f62010-12-29 16:00:25 +0200331 list_del(&cmd->list);
332 mgmt_pending_free(cmd);
333}
334
Szymon Janc4e51eae2011-02-25 19:05:48 +0100335static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200337 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300339 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341
342 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
Szymon Janc4e51eae2011-02-25 19:05:48 +0100344 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100346 if (len != sizeof(*cp))
347 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
348
Szymon Janc4e51eae2011-02-25 19:05:48 +0100349 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200354
355 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200356 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100357 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200358 goto failed;
359 }
360
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
362 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363 goto failed;
364 }
365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300367 if (!cmd) {
368 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200369 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300370 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200371
Johan Hedberg72a734e2010-12-30 00:38:22 +0200372 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200373 queue_work(hdev->workqueue, &hdev->power_on);
374 else
375 queue_work(hdev->workqueue, &hdev->power_off);
376
Johan Hedberg366a0332011-02-19 12:05:55 -0300377 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200378
379failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200381 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300382 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200383}
384
Szymon Janc4e51eae2011-02-25 19:05:48 +0100385static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
386 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200388 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200389 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300390 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391 u8 scan;
392 int err;
393
394 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
Szymon Janc4e51eae2011-02-25 19:05:48 +0100396 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200397
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100398 if (len != sizeof(*cp))
399 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
400
Szymon Janc4e51eae2011-02-25 19:05:48 +0100401 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200402 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100403 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200406
407 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100408 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200409 goto failed;
410 }
411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
413 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
414 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200415 goto failed;
416 }
417
Johan Hedberg72a734e2010-12-30 00:38:22 +0200418 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200419 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100420 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200421 goto failed;
422 }
423
Szymon Janc4e51eae2011-02-25 19:05:48 +0100424 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300425 if (!cmd) {
426 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200427 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300428 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200429
430 scan = SCAN_PAGE;
431
Johan Hedberg72a734e2010-12-30 00:38:22 +0200432 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200433 scan |= SCAN_INQUIRY;
434
435 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
436 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300437 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200438
439failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200441 hci_dev_put(hdev);
442
443 return err;
444}
445
Szymon Janc4e51eae2011-02-25 19:05:48 +0100446static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
447 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200449 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 u8 scan;
453 int err;
454
455 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456
Szymon Janc4e51eae2011-02-25 19:05:48 +0100457 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200458
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100459 if (len != sizeof(*cp))
460 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
461
Szymon Janc4e51eae2011-02-25 19:05:48 +0100462 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100464 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200467
468 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100469 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200470 goto failed;
471 }
472
Szymon Janc4e51eae2011-02-25 19:05:48 +0100473 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
474 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
475 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200476 goto failed;
477 }
478
Johan Hedberg72a734e2010-12-30 00:38:22 +0200479 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100480 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200481 goto failed;
482 }
483
Szymon Janc4e51eae2011-02-25 19:05:48 +0100484 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300485 if (!cmd) {
486 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200487 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300488 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200489
Johan Hedberg72a734e2010-12-30 00:38:22 +0200490 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200491 scan = SCAN_PAGE;
492 else
493 scan = 0;
494
495 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
496 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300497 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200498
499failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200501 hci_dev_put(hdev);
502
503 return err;
504}
505
Szymon Janc4e51eae2011-02-25 19:05:48 +0100506static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
507 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200508{
509 struct sk_buff *skb;
510 struct mgmt_hdr *hdr;
511
Brian Gixa68668b2011-08-11 15:49:36 -0700512 BT_DBG("hci%d %d", index, event);
513
Johan Hedbergc542a062011-01-26 13:11:03 +0200514 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
515 if (!skb)
516 return -ENOMEM;
517
518 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
519
520 hdr = (void *) skb_put(skb, sizeof(*hdr));
521 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523 hdr->len = cpu_to_le16(data_len);
524
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 if (data)
526 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200527
528 hci_send_to_sock(NULL, skb, skip_sk);
529 kfree_skb(skb);
530
531 return 0;
532}
533
Johan Hedberg053f0212011-01-26 13:07:10 +0200534static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
535{
Johan Hedberga38528f2011-01-22 06:46:43 +0200536 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200537
Johan Hedberga38528f2011-01-22 06:46:43 +0200538 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200539
Szymon Janc4e51eae2011-02-25 19:05:48 +0100540 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200541}
542
Szymon Janc4e51eae2011-02-25 19:05:48 +0100543static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
544 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200545{
546 struct mgmt_mode *cp, ev;
547 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200548 int err;
549
550 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200551
Szymon Janc4e51eae2011-02-25 19:05:48 +0100552 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200553
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100554 if (len != sizeof(*cp))
555 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
556
Szymon Janc4e51eae2011-02-25 19:05:48 +0100557 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200558 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100559 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200562
563 if (cp->val)
564 set_bit(HCI_PAIRABLE, &hdev->flags);
565 else
566 clear_bit(HCI_PAIRABLE, &hdev->flags);
567
Szymon Janc4e51eae2011-02-25 19:05:48 +0100568 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200569 if (err < 0)
570 goto failed;
571
Johan Hedbergc542a062011-01-26 13:11:03 +0200572 ev.val = cp->val;
573
Szymon Janc4e51eae2011-02-25 19:05:48 +0100574 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200575
576failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200578 hci_dev_put(hdev);
579
580 return err;
581}
582
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300583#define EIR_FLAGS 0x01 /* flags */
584#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
585#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
586#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
587#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
588#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
589#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
590#define EIR_NAME_SHORT 0x08 /* shortened local name */
591#define EIR_NAME_COMPLETE 0x09 /* complete local name */
592#define EIR_TX_POWER 0x0A /* transmit power level */
593#define EIR_DEVICE_ID 0x10 /* device ID */
594
595#define PNP_INFO_SVCLASS_ID 0x1200
596
597static u8 bluetooth_base_uuid[] = {
598 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
599 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600};
601
602static u16 get_uuid16(u8 *uuid128)
603{
604 u32 val;
605 int i;
606
607 for (i = 0; i < 12; i++) {
608 if (bluetooth_base_uuid[i] != uuid128[i])
609 return 0;
610 }
611
612 memcpy(&val, &uuid128[12], 4);
613
614 val = le32_to_cpu(val);
615 if (val > 0xffff)
616 return 0;
617
618 return (u16) val;
619}
620
621static void create_eir(struct hci_dev *hdev, u8 *data)
622{
623 u8 *ptr = data;
624 u16 eir_len = 0;
625 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
626 int i, truncated = 0;
627 struct list_head *p;
628 size_t name_len;
629
630 name_len = strlen(hdev->dev_name);
631
632 if (name_len > 0) {
633 /* EIR Data type */
634 if (name_len > 48) {
635 name_len = 48;
636 ptr[1] = EIR_NAME_SHORT;
637 } else
638 ptr[1] = EIR_NAME_COMPLETE;
639
640 /* EIR Data length */
641 ptr[0] = name_len + 1;
642
643 memcpy(ptr + 2, hdev->dev_name, name_len);
644
645 eir_len += (name_len + 2);
646 ptr += (name_len + 2);
647 }
648
649 memset(uuid16_list, 0, sizeof(uuid16_list));
650
651 /* Group all UUID16 types */
652 list_for_each(p, &hdev->uuids) {
653 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
654 u16 uuid16;
655
656 uuid16 = get_uuid16(uuid->uuid);
657 if (uuid16 == 0)
658 return;
659
660 if (uuid16 < 0x1100)
661 continue;
662
663 if (uuid16 == PNP_INFO_SVCLASS_ID)
664 continue;
665
666 /* Stop if not enough space to put next UUID */
667 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
668 truncated = 1;
669 break;
670 }
671
672 /* Check for duplicates */
673 for (i = 0; uuid16_list[i] != 0; i++)
674 if (uuid16_list[i] == uuid16)
675 break;
676
677 if (uuid16_list[i] == 0) {
678 uuid16_list[i] = uuid16;
679 eir_len += sizeof(u16);
680 }
681 }
682
683 if (uuid16_list[0] != 0) {
684 u8 *length = ptr;
685
686 /* EIR Data type */
687 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
688
689 ptr += 2;
690 eir_len += 2;
691
692 for (i = 0; uuid16_list[i] != 0; i++) {
693 *ptr++ = (uuid16_list[i] & 0x00ff);
694 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
695 }
696
697 /* EIR Data length */
698 *length = (i * sizeof(u16)) + 1;
699 }
700}
701
702static int update_eir(struct hci_dev *hdev)
703{
704 struct hci_cp_write_eir cp;
705
706 if (!(hdev->features[6] & LMP_EXT_INQ))
707 return 0;
708
709 if (hdev->ssp_mode == 0)
710 return 0;
711
712 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
713 return 0;
714
715 memset(&cp, 0, sizeof(cp));
716
717 create_eir(hdev, cp.data);
718
719 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
720 return 0;
721
722 memcpy(hdev->eir, cp.data, sizeof(cp.data));
723
724 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
725}
726
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200727static u8 get_service_classes(struct hci_dev *hdev)
728{
729 struct list_head *p;
730 u8 val = 0;
731
732 list_for_each(p, &hdev->uuids) {
733 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
734
735 val |= uuid->svc_hint;
736 }
737
738 return val;
739}
740
741static int update_class(struct hci_dev *hdev)
742{
743 u8 cod[3];
744
745 BT_DBG("%s", hdev->name);
746
747 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
748 return 0;
749
750 cod[0] = hdev->minor_class;
751 cod[1] = hdev->major_class;
752 cod[2] = get_service_classes(hdev);
753
754 if (memcmp(cod, hdev->dev_class, 3) == 0)
755 return 0;
756
757 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
758}
759
Szymon Janc4e51eae2011-02-25 19:05:48 +0100760static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200761{
762 struct mgmt_cp_add_uuid *cp;
763 struct hci_dev *hdev;
764 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200765 int err;
766
767 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768
Szymon Janc4e51eae2011-02-25 19:05:48 +0100769 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200770
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100771 if (len != sizeof(*cp))
772 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
773
Szymon Janc4e51eae2011-02-25 19:05:48 +0100774 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200775 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100776 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200779
780 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
781 if (!uuid) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788
789 list_add(&uuid->list, &hdev->uuids);
790
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200791 err = update_class(hdev);
792 if (err < 0)
793 goto failed;
794
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300795 err = update_eir(hdev);
796 if (err < 0)
797 goto failed;
798
Szymon Janc4e51eae2011-02-25 19:05:48 +0100799 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200800
801failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200803 hci_dev_put(hdev);
804
805 return err;
806}
807
Szymon Janc4e51eae2011-02-25 19:05:48 +0100808static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200809{
810 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100811 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200812 struct hci_dev *hdev;
813 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 +0200814 int err, found;
815
816 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200817
Szymon Janc4e51eae2011-02-25 19:05:48 +0100818 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200819
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100820 if (len != sizeof(*cp))
821 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
822
Szymon Janc4e51eae2011-02-25 19:05:48 +0100823 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200824 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100825 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200828
829 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
830 err = hci_uuids_clear(hdev);
831 goto unlock;
832 }
833
834 found = 0;
835
836 list_for_each_safe(p, n, &hdev->uuids) {
837 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
838
839 if (memcmp(match->uuid, cp->uuid, 16) != 0)
840 continue;
841
842 list_del(&match->list);
843 found++;
844 }
845
846 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100847 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200848 goto unlock;
849 }
850
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851 err = update_class(hdev);
852 if (err < 0)
853 goto unlock;
854
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300855 err = update_eir(hdev);
856 if (err < 0)
857 goto unlock;
858
Szymon Janc4e51eae2011-02-25 19:05:48 +0100859 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200860
861unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200863 hci_dev_put(hdev);
864
865 return err;
866}
867
Szymon Janc4e51eae2011-02-25 19:05:48 +0100868static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
869 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870{
871 struct hci_dev *hdev;
872 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873 int err;
874
875 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100879 if (len != sizeof(*cp))
880 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887
888 hdev->major_class = cp->major;
889 hdev->minor_class = cp->minor;
890
891 err = update_class(hdev);
892
893 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100894 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897 hci_dev_put(hdev);
898
899 return err;
900}
901
Szymon Janc4e51eae2011-02-25 19:05:48 +0100902static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
903 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904{
905 struct hci_dev *hdev;
906 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200907 int err;
908
909 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200910
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100911 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100912 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200915 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200919
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200921
922 if (cp->enable) {
923 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
924 err = 0;
925 } else {
926 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
927 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300928 if (err == 0)
929 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200930 }
931
932 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
934 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200937 hci_dev_put(hdev);
938
939 return err;
940}
941
Szymon Janc4e51eae2011-02-25 19:05:48 +0100942static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200943{
944 struct hci_dev *hdev;
945 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100946 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300947 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200948
949 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100950
951 if (len < sizeof(*cp))
952 return -EINVAL;
953
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200954 key_count = get_unaligned_le16(&cp->key_count);
955
956 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300957 if (expected_len > len) {
958 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
959 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200960 return -EINVAL;
961 }
962
Szymon Janc4e51eae2011-02-25 19:05:48 +0100963 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200964 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100965 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200966
Szymon Janc4e51eae2011-02-25 19:05:48 +0100967 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200968 key_count);
969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200971
972 hci_link_keys_clear(hdev);
973
974 set_bit(HCI_LINK_KEYS, &hdev->flags);
975
976 if (cp->debug_keys)
977 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
978 else
979 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
980
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300981 len -= sizeof(*cp);
982 i = 0;
983
984 while (i < len) {
985 struct mgmt_key_info *key = (void *) cp->keys + i;
986
Brian Gixa68668b2011-08-11 15:49:36 -0700987 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300990 struct key_master_id *id = (void *) key->data;
991
992 if (key->dlen != sizeof(struct key_master_id))
993 continue;
994
Vinicius Costa Gomes1fa2de32011-07-08 18:31:45 -0300995 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
Brian Gixa68668b2011-08-11 15:49:36 -0700996 key->auth, id->ediv, id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -0300997
998 continue;
999 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001002 key->pin_len);
1003 }
1004
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001005 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001008 hci_dev_put(hdev);
1009
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001010 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001011}
1012
Szymon Janc4e51eae2011-02-25 19:05:48 +01001013static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001014{
1015 struct hci_dev *hdev;
1016 struct mgmt_cp_remove_key *cp;
1017 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001018 int err;
1019
1020 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001021
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001022 if (len != sizeof(*cp))
1023 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1024
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001026 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001030
1031 err = hci_remove_link_key(hdev, &cp->bdaddr);
1032 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001034 goto unlock;
1035 }
1036
1037 err = 0;
1038
1039 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1040 goto unlock;
1041
1042 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1043 if (conn) {
1044 struct hci_cp_disconnect dc;
1045
1046 put_unaligned_le16(conn->handle, &dc.handle);
1047 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001049 }
1050
1051unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001053 hci_dev_put(hdev);
1054
1055 return err;
1056}
1057
Szymon Janc4e51eae2011-02-25 19:05:48 +01001058static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059{
1060 struct hci_dev *hdev;
1061 struct mgmt_cp_disconnect *cp;
1062 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001063 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001065 int err;
1066
1067 BT_DBG("");
1068
1069 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001070
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001071 if (len != sizeof(*cp))
1072 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1073
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001075 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001079
1080 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001082 goto failed;
1083 }
1084
Szymon Janc4e51eae2011-02-25 19:05:48 +01001085 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1086 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001087 goto failed;
1088 }
1089
1090 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1091 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001092 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1093 if (!conn) {
1094 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1095 ENOTCONN);
1096 goto failed;
1097 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001098 }
1099
Szymon Janc4e51eae2011-02-25 19:05:48 +01001100 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001101 if (!cmd) {
1102 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001103 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001104 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001105
1106 put_unaligned_le16(conn->handle, &dc.handle);
1107 dc.reason = 0x13; /* Remote User Terminated Connection */
1108
1109 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1110 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001111 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001112
1113failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001115 hci_dev_put(hdev);
1116
1117 return err;
1118}
1119
Szymon Janc8ce62842011-03-01 16:55:32 +01001120static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001121{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001122 struct mgmt_rp_get_connections *rp;
1123 struct hci_dev *hdev;
1124 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001125 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001126 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001127 int i, err;
1128
1129 BT_DBG("");
1130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001132 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001133 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001136
1137 count = 0;
1138 list_for_each(p, &hdev->conn_hash.list) {
1139 count++;
1140 }
1141
Johan Hedberga38528f2011-01-22 06:46:43 +02001142 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1143 rp = kmalloc(rp_len, GFP_ATOMIC);
1144 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001145 err = -ENOMEM;
1146 goto unlock;
1147 }
1148
Johan Hedberg2784eb42011-01-21 13:56:35 +02001149 put_unaligned_le16(count, &rp->conn_count);
1150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 read_lock(&hci_dev_list_lock);
1152
Johan Hedberg2784eb42011-01-21 13:56:35 +02001153 i = 0;
1154 list_for_each(p, &hdev->conn_hash.list) {
1155 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1156
1157 bacpy(&rp->conn[i++], &c->dst);
1158 }
1159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 read_unlock(&hci_dev_list_lock);
1161
Szymon Janc4e51eae2011-02-25 19:05:48 +01001162 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001163
1164unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001165 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001167 hci_dev_put(hdev);
1168 return err;
1169}
1170
Szymon Janc4e51eae2011-02-25 19:05:48 +01001171static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1172 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001173{
1174 struct hci_dev *hdev;
1175 struct mgmt_cp_pin_code_reply *cp;
1176 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001177 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001178 int err;
1179
1180 BT_DBG("");
1181
1182 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001183
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001184 if (len != sizeof(*cp))
1185 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1186
Szymon Janc4e51eae2011-02-25 19:05:48 +01001187 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001189 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001192
1193 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001194 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 goto failed;
1196 }
1197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001199 if (!cmd) {
1200 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001201 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001202 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203
1204 bacpy(&reply.bdaddr, &cp->bdaddr);
1205 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001207
1208 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1209 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001210 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001211
1212failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001214 hci_dev_put(hdev);
1215
1216 return err;
1217}
1218
Szymon Janc4e51eae2011-02-25 19:05:48 +01001219static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1220 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221{
1222 struct hci_dev *hdev;
1223 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001225 int err;
1226
1227 BT_DBG("");
1228
1229 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001231 if (len != sizeof(*cp))
1232 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1233 EINVAL);
1234
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001236 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1238 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001241
1242 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1244 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001245 goto failed;
1246 }
1247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1249 data, len);
1250 if (!cmd) {
1251 err = -ENOMEM;
1252 goto failed;
1253 }
1254
1255 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1256 &cp->bdaddr);
1257 if (err < 0)
1258 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001259
1260failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001262 hci_dev_put(hdev);
1263
1264 return err;
1265}
1266
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1268 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001269{
1270 struct hci_dev *hdev;
1271 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001272
1273 BT_DBG("");
1274
1275 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001276
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001277 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001278 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001279
Szymon Janc4e51eae2011-02-25 19:05:48 +01001280 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001281 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001282 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001285
1286 hdev->io_capability = cp->io_capability;
1287
1288 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001289 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001292 hci_dev_put(hdev);
1293
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001295}
1296
Johan Hedberge9a416b2011-02-19 12:05:56 -03001297static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1298{
1299 struct hci_dev *hdev = conn->hdev;
1300 struct list_head *p;
1301
1302 list_for_each(p, &cmd_list) {
1303 struct pending_cmd *cmd;
1304
1305 cmd = list_entry(p, struct pending_cmd, list);
1306
1307 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1308 continue;
1309
1310 if (cmd->index != hdev->id)
1311 continue;
1312
1313 if (cmd->user_data != conn)
1314 continue;
1315
1316 return cmd;
1317 }
1318
1319 return NULL;
1320}
1321
1322static void pairing_complete(struct pending_cmd *cmd, u8 status)
1323{
1324 struct mgmt_rp_pair_device rp;
1325 struct hci_conn *conn = cmd->user_data;
1326
Brian Gixa68668b2011-08-11 15:49:36 -07001327 BT_DBG(" %u", status);
1328
Johan Hedberge9a416b2011-02-19 12:05:56 -03001329 bacpy(&rp.bdaddr, &conn->dst);
1330 rp.status = status;
1331
Szymon Janc4e51eae2011-02-25 19:05:48 +01001332 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333
1334 /* So we don't get further callbacks for this connection */
1335 conn->connect_cfm_cb = NULL;
1336 conn->security_cfm_cb = NULL;
1337 conn->disconn_cfm_cb = NULL;
1338
1339 hci_conn_put(conn);
1340
Johan Hedberga664b5b2011-02-19 12:06:02 -03001341 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001342}
1343
1344static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1345{
1346 struct pending_cmd *cmd;
1347
Brian Gixa68668b2011-08-11 15:49:36 -07001348 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349
1350 cmd = find_pairing(conn);
1351 if (!cmd) {
1352 BT_DBG("Unable to find a pending command");
1353 return;
1354 }
1355
1356 pairing_complete(cmd, status);
1357}
1358
Brian Gixa68668b2011-08-11 15:49:36 -07001359static void security_complete_cb(struct hci_conn *conn, u8 status)
1360{
1361 struct pending_cmd *cmd;
1362
1363 BT_DBG(" %u", status);
1364
1365 cmd = find_pairing(conn);
1366 if (!cmd) {
1367 BT_DBG("Unable to find a pending command");
1368 return;
1369 }
1370
1371 if (conn->type == LE_LINK)
1372 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1373 status ? 0 : 1);
1374 else
1375 pairing_complete(cmd, status);
1376}
1377
1378static void connect_complete_cb(struct hci_conn *conn, u8 status)
1379{
1380 struct pending_cmd *cmd;
1381
1382 BT_DBG("conn: %p %u", conn, status);
1383
1384 cmd = find_pairing(conn);
1385 if (!cmd) {
1386 BT_DBG("Unable to find a pending command");
1387 return;
1388 }
Brian Gixa68668b2011-08-11 15:49:36 -07001389}
1390
1391static void discovery_terminated(struct pending_cmd *cmd, void *data)
1392{
1393 struct mgmt_mode ev = {0};
1394 struct disco_interleave *ilp = cmd->param;
1395
1396 BT_DBG("");
1397 del_timer_sync(&ilp->le_timer);
1398 del_timer_sync(&ilp->timer);
1399 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1400
1401 list_del(&cmd->list);
1402
1403 mgmt_pending_free(cmd);
1404}
1405
Szymon Janc4e51eae2011-02-25 19:05:48 +01001406static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001407{
1408 struct hci_dev *hdev;
1409 struct mgmt_cp_pair_device *cp;
1410 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001411 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001412 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001413 int err;
1414
1415 BT_DBG("");
1416
Brian Gix64bd5302011-09-08 11:35:48 -07001417 cp = (void *) data;
1418
1419 if (len != sizeof(*cp))
1420 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001423
Johan Hedberge9a416b2011-02-19 12:05:56 -03001424 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001428
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301429 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1430 io_cap = cp->io_cap;
1431 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001432 sec_level = BT_SECURITY_MEDIUM;
1433 auth_type = HCI_AT_DEDICATED_BONDING;
1434 } else {
1435 sec_level = BT_SECURITY_HIGH;
1436 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1437 }
1438
Brian Gixa68668b2011-08-11 15:49:36 -07001439 if (hci_find_adv_entry(hdev, &cp->bdaddr)) {
1440 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1441 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001442 } else {
1443 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1444 if (io_cap == 0x04)
1445 io_cap = 0x01;
1446 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1447 auth_type);
1448 }
1449
Ville Tervo30e76272011-02-22 16:10:53 -03001450 if (IS_ERR(conn)) {
1451 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001452 goto unlock;
1453 }
1454
1455 if (conn->connect_cfm_cb) {
1456 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001458 goto unlock;
1459 }
1460
Szymon Janc4e51eae2011-02-25 19:05:48 +01001461 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001462 if (!cmd) {
1463 err = -ENOMEM;
1464 hci_conn_put(conn);
1465 goto unlock;
1466 }
1467
Brian Gixa68668b2011-08-11 15:49:36 -07001468 conn->connect_cfm_cb = connect_complete_cb;
1469 conn->security_cfm_cb = security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001470 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001471 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001472 cmd->user_data = conn;
1473
1474 if (conn->state == BT_CONNECTED &&
1475 hci_conn_security(conn, sec_level, auth_type))
1476 pairing_complete(cmd, 0);
1477
1478 err = 0;
1479
1480unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001482 hci_dev_put(hdev);
1483
1484 return err;
1485}
1486
Szymon Janc4e51eae2011-02-25 19:05:48 +01001487static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001488 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001489{
1490 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001491 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001492 struct pending_cmd *cmd;
1493 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001494 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001495 int err;
1496
Brian Gixa68668b2011-08-11 15:49:36 -07001497 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001498
Brian Gixa68668b2011-08-11 15:49:36 -07001499 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001500 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001501 else
1502 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001503
Brian Gixa68668b2011-08-11 15:49:36 -07001504 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001505 return cmd_status(sk, index, mgmt_op, EINVAL);
1506
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001508 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001509 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001512
Johan Hedberga5c29682011-02-19 12:05:57 -03001513 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001514 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001515 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001516 }
1517
Brian Gixa68668b2011-08-11 15:49:36 -07001518 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1519 if (le_conn) {
1520 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1521 goto done;
1522 }
1523 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1524 "Reject" : "Accept");
1525
Szymon Janc4e51eae2011-02-25 19:05:48 +01001526 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001527 if (!cmd) {
1528 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001529 goto done;
1530 }
1531
1532 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1533 if (err < 0)
1534 mgmt_pending_remove(cmd);
1535
1536done:
1537 hci_dev_unlock(hdev);
1538 hci_dev_put(hdev);
1539
1540 return err;
1541}
1542
1543static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1544 u16 len)
1545{
1546 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1547 struct hci_cp_remote_name_req hci_cp;
1548 struct hci_dev *hdev;
1549 struct pending_cmd *cmd;
1550 int err;
1551
1552 BT_DBG("");
1553
1554 if (len != sizeof(*mgmt_cp))
1555 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1556
1557 hdev = hci_dev_get(index);
1558 if (!hdev)
1559 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1560
1561 hci_dev_lock(hdev);
1562
1563 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1564 if (!cmd) {
1565 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001566 goto failed;
1567 }
1568
Brian Gixa68668b2011-08-11 15:49:36 -07001569 memset(&hci_cp, 0, sizeof(hci_cp));
1570 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1571 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1572 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001573 if (err < 0)
1574 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001575
1576failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001578 hci_dev_put(hdev);
1579
1580 return err;
1581}
1582
Johan Hedbergb312b1612011-03-16 14:29:37 +02001583static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1584 u16 len)
1585{
1586 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1587 struct hci_cp_write_local_name hci_cp;
1588 struct hci_dev *hdev;
1589 struct pending_cmd *cmd;
1590 int err;
1591
1592 BT_DBG("");
1593
1594 if (len != sizeof(*mgmt_cp))
1595 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1596
1597 hdev = hci_dev_get(index);
1598 if (!hdev)
1599 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001602
1603 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1604 if (!cmd) {
1605 err = -ENOMEM;
1606 goto failed;
1607 }
1608
1609 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1610 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1611 &hci_cp);
1612 if (err < 0)
1613 mgmt_pending_remove(cmd);
1614
1615failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001617 hci_dev_put(hdev);
1618
1619 return err;
1620}
1621
Brian Gixa68668b2011-08-11 15:49:36 -07001622static void discovery_rsp(struct pending_cmd *cmd, void *data)
1623{
1624 struct mgmt_mode ev;
1625
1626 BT_DBG("");
1627 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1628 ev.val = 1;
1629 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1630 } else {
1631 ev.val = 0;
1632 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1633 NULL, 0);
1634 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1635 struct disco_interleave *ilp = cmd->param;
1636
1637 del_timer_sync(&ilp->le_timer);
1638 del_timer_sync(&ilp->timer);
1639 }
1640 }
1641
1642 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1643
1644 list_del(&cmd->list);
1645
1646 mgmt_pending_free(cmd);
1647}
1648
1649void mgmt_inquiry_started(u16 index)
1650{
1651 BT_DBG("");
1652 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1653 discovery_rsp, NULL);
1654}
1655
1656void mgmt_inquiry_complete_evt(u16 index, u8 status)
1657{
1658 struct hci_dev *hdev;
1659 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1660 struct pending_cmd *cmd;
1661 int err = -1;
1662
1663 BT_DBG("");
1664
1665 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001666
1667 if (hdev)
1668 hci_dev_lock(hdev);
1669
Brian Gixa68668b2011-08-11 15:49:36 -07001670 if (!hdev || !lmp_le_capable(hdev)) {
1671 struct mgmt_mode cp = {0};
1672
1673 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1674 discovery_terminated, NULL);
1675
1676 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001677
Brian Gix64bd5302011-09-08 11:35:48 -07001678 if (hdev)
1679 goto done;
1680 else
1681 return;
1682 }
Brian Gixa68668b2011-08-11 15:49:36 -07001683
1684 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1685 if (cmd && cmd->param) {
1686 struct disco_interleave *ilp = cmd->param;
1687
1688 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1689 sizeof(le_cp), &le_cp);
1690 if (err >= 0) {
1691 mod_timer(&ilp->le_timer, jiffies +
1692 msecs_to_jiffies(ilp->int_phase * 1000));
1693 ilp->mode = SCAN_LE;
1694 } else
1695 ilp->mode = SCAN_IDLE;
1696 }
1697
1698 if (err < 0)
1699 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1700 discovery_terminated, NULL);
1701
Brian Gix64bd5302011-09-08 11:35:48 -07001702done:
Brian Gixa68668b2011-08-11 15:49:36 -07001703 hci_dev_unlock(hdev);
1704 hci_dev_put(hdev);
1705}
1706
1707static void disco_to(unsigned long data)
1708{
1709 struct disco_interleave *ilp = (void *)data;
1710 struct hci_dev *hdev;
1711 struct pending_cmd *cmd;
1712
1713 BT_DBG("hci%d", ilp->index);
1714
1715 del_timer_sync(&ilp->le_timer);
1716 hdev = hci_dev_get(ilp->index);
1717
1718 if (hdev) {
1719 hci_dev_lock(hdev);
1720
1721 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1722
1723 if (ilp->mode != SCAN_IDLE) {
1724 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1725
1726 if (ilp->mode == SCAN_LE)
1727 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1728 sizeof(le_cp), &le_cp);
1729 else
1730 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1731 0, NULL);
1732
1733 ilp->mode = SCAN_IDLE;
1734 }
1735
1736 if (cmd) {
1737 struct mgmt_mode cp = {0};
1738
1739 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1740 sizeof(cp), NULL);
1741 mgmt_pending_remove(cmd);
1742 }
1743
1744 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001745 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001746 }
1747}
1748
1749static void disco_le_to(unsigned long data)
1750{
1751 struct disco_interleave *ilp = (void *)data;
1752 struct hci_dev *hdev;
1753 struct pending_cmd *cmd;
1754 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1755
1756 BT_DBG("hci%d", ilp->index);
1757
1758 hdev = hci_dev_get(ilp->index);
1759 del_timer_sync(&ilp->le_timer);
1760
1761 if (hdev) {
1762 hci_dev_lock(hdev);
1763
1764 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1765
1766 if (ilp->mode == SCAN_LE)
1767 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1768 sizeof(le_cp), &le_cp);
1769
1770 /* re-start BR scan */
1771 if (cmd) {
1772 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1773 ilp->int_phase *= 2;
1774 ilp->int_count = 0;
1775 cp.num_rsp = (u8) ilp->int_phase;
1776 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1777 ilp->mode = SCAN_BR;
1778 } else
1779 ilp->mode = SCAN_IDLE;
1780
1781 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001782 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001783 }
1784}
1785
1786static int start_discovery(struct sock *sk, u16 index)
1787{
1788 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1789 struct hci_dev *hdev;
1790 struct pending_cmd *cmd;
1791 int err;
1792
1793 BT_DBG("");
1794
1795 hdev = hci_dev_get(index);
1796 if (!hdev)
1797 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1798
1799 hci_dev_lock(hdev);
1800
1801 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1802 if (!cmd) {
1803 err = -ENOMEM;
1804 goto failed;
1805 }
1806
1807 /* If LE Capable, we will alternate between BR/EDR and LE */
1808 if (lmp_le_capable(hdev)) {
1809 struct hci_cp_le_set_scan_parameters le_cp;
1810
1811 /* Shorten BR scan params */
1812 cp.num_rsp = 1;
1813 cp.length /= 2;
1814
1815 /* Setup LE scan params */
1816 memset(&le_cp, 0, sizeof(le_cp));
1817 le_cp.type = 0x01; /* Active scanning */
1818 /* The recommended value for scan interval and window is
1819 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1820 le_cp.interval = cpu_to_le16(0x0012);
1821 le_cp.window = cpu_to_le16(0x0012);
1822 le_cp.own_bdaddr_type = 0; /* Public address */
1823 le_cp.filter = 0; /* Accept all adv packets */
1824
1825 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1826 sizeof(le_cp), &le_cp);
1827 }
1828
1829 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1830
1831 if (err < 0)
1832 mgmt_pending_remove(cmd);
1833 else if (lmp_le_capable(hdev)) {
1834 struct disco_interleave il, *ilp;
1835
1836 il.int_phase = 1;
1837 il.int_count = 0;
1838 il.index = index;
1839 il.mode = SCAN_BR;
1840 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1841 sizeof(struct disco_interleave));
1842 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1843 if (cmd) {
1844 ilp = cmd->param;
1845 setup_timer(&ilp->le_timer, disco_le_to,
1846 (unsigned long) ilp);
1847 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1848 mod_timer(&ilp->timer,
1849 jiffies + msecs_to_jiffies(20000));
1850 }
1851 }
1852
1853failed:
1854 hci_dev_unlock(hdev);
1855 hci_dev_put(hdev);
1856
1857 return err;
1858}
1859
1860static int stop_discovery(struct sock *sk, u16 index)
1861{
1862 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1863 struct mgmt_mode mode_cp = {0};
1864 struct disco_interleave *ilp = NULL;
1865 struct hci_dev *hdev;
1866 struct pending_cmd *cmd = NULL;
1867 int err = -EPERM;
1868
1869 BT_DBG("");
1870
1871 hdev = hci_dev_get(index);
1872 if (!hdev)
1873 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1874
1875 hci_dev_lock(hdev);
1876
1877 if (lmp_le_capable(hdev)) {
1878 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1879 if (!cmd) {
1880 err = -ENOMEM;
1881 goto failed;
1882 }
1883
1884 ilp = cmd->param;
1885 }
1886
1887 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1888 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1889 sizeof(le_cp), &le_cp);
1890
1891 if (err < 0) {
1892 if (!ilp || (ilp->mode == SCAN_BR))
1893 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1894 0, NULL);
1895 }
1896
1897 if (ilp) {
1898 ilp->mode = SCAN_IDLE;
1899 del_timer_sync(&ilp->le_timer);
1900 del_timer_sync(&ilp->timer);
1901 }
1902
1903 if (err < 0 && cmd)
1904 mgmt_pending_remove(cmd);
1905
1906 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1907
1908failed:
1909 hci_dev_unlock(hdev);
1910 hci_dev_put(hdev);
1911
1912 if (err < 0)
1913 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1914 else
1915 return err;
1916}
1917
Szymon Jancc35938b2011-03-22 13:12:21 +01001918static int read_local_oob_data(struct sock *sk, u16 index)
1919{
1920 struct hci_dev *hdev;
1921 struct pending_cmd *cmd;
1922 int err;
1923
1924 BT_DBG("hci%u", index);
1925
1926 hdev = hci_dev_get(index);
1927 if (!hdev)
1928 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1929 ENODEV);
1930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001932
1933 if (!test_bit(HCI_UP, &hdev->flags)) {
1934 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1935 ENETDOWN);
1936 goto unlock;
1937 }
1938
1939 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1940 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1941 EOPNOTSUPP);
1942 goto unlock;
1943 }
1944
1945 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1946 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1947 goto unlock;
1948 }
1949
1950 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1951 if (!cmd) {
1952 err = -ENOMEM;
1953 goto unlock;
1954 }
1955
1956 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1957 if (err < 0)
1958 mgmt_pending_remove(cmd);
1959
1960unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001962 hci_dev_put(hdev);
1963
1964 return err;
1965}
1966
Szymon Janc2763eda2011-03-22 13:12:22 +01001967static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1968 u16 len)
1969{
1970 struct hci_dev *hdev;
1971 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1972 int err;
1973
1974 BT_DBG("hci%u ", index);
1975
1976 if (len != sizeof(*cp))
1977 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1978 EINVAL);
1979
1980 hdev = hci_dev_get(index);
1981 if (!hdev)
1982 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1983 ENODEV);
1984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001986
1987 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1988 cp->randomizer);
1989 if (err < 0)
1990 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1991 else
1992 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1993 0);
1994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001995 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001996 hci_dev_put(hdev);
1997
1998 return err;
1999}
2000
2001static int remove_remote_oob_data(struct sock *sk, u16 index,
2002 unsigned char *data, u16 len)
2003{
2004 struct hci_dev *hdev;
2005 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2006 int err;
2007
2008 BT_DBG("hci%u ", index);
2009
2010 if (len != sizeof(*cp))
2011 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2012 EINVAL);
2013
2014 hdev = hci_dev_get(index);
2015 if (!hdev)
2016 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2017 ENODEV);
2018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002020
2021 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2022 if (err < 0)
2023 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2024 -err);
2025 else
2026 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2027 NULL, 0);
2028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002030 hci_dev_put(hdev);
2031
2032 return err;
2033}
2034
Johan Hedberg03811012010-12-08 00:21:06 +02002035int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2036{
2037 unsigned char *buf;
2038 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002039 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002040 int err;
2041
2042 BT_DBG("got %zu bytes", msglen);
2043
2044 if (msglen < sizeof(*hdr))
2045 return -EINVAL;
2046
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002047 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002048 if (!buf)
2049 return -ENOMEM;
2050
2051 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2052 err = -EFAULT;
2053 goto done;
2054 }
2055
2056 hdr = (struct mgmt_hdr *) buf;
2057 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002058 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002059 len = get_unaligned_le16(&hdr->len);
2060
2061 if (len != msglen - sizeof(*hdr)) {
2062 err = -EINVAL;
2063 goto done;
2064 }
2065
Brian Gixa68668b2011-08-11 15:49:36 -07002066 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002067 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002068 case MGMT_OP_READ_VERSION:
2069 err = read_version(sk);
2070 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002071 case MGMT_OP_READ_INDEX_LIST:
2072 err = read_index_list(sk);
2073 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002074 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002075 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002076 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002077 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002078 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002079 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002080 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002081 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002082 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002083 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002084 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002085 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002086 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002087 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002088 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002090 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002091 break;
2092 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002093 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002095 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002096 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002097 break;
2098 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002099 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002100 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002101 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002103 break;
2104 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002105 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002106 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002107 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002108 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002109 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002111 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002112 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002113 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002114 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002115 break;
2116 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002118 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002119 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002121 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002122 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002123 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002124 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002125 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002126 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002127 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002128 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2129 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002130 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002131 case MGMT_OP_SET_LOCAL_NAME:
2132 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2133 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002134 case MGMT_OP_START_DISCOVERY:
2135 err = start_discovery(sk, index);
2136 break;
2137 case MGMT_OP_STOP_DISCOVERY:
2138 err = stop_discovery(sk, index);
2139 break;
2140 case MGMT_OP_RESOLVE_NAME:
2141 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2142 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002143 case MGMT_OP_READ_LOCAL_OOB_DATA:
2144 err = read_local_oob_data(sk, index);
2145 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002146 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2147 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2148 break;
2149 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2150 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2151 len);
2152 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153
Johan Hedberg03811012010-12-08 00:21:06 +02002154 default:
2155 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002157 break;
2158 }
2159
Johan Hedberge41d8b42010-12-13 21:07:03 +02002160 if (err < 0)
2161 goto done;
2162
Johan Hedberg03811012010-12-08 00:21:06 +02002163 err = msglen;
2164
2165done:
2166 kfree(buf);
2167 return err;
2168}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002169
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002170int mgmt_index_added(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_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002174}
2175
2176int mgmt_index_removed(u16 index)
2177{
Brian Gixa68668b2011-08-11 15:49:36 -07002178 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002179 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002180}
2181
Johan Hedberg73f22f62010-12-29 16:00:25 +02002182struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002183 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002184 struct sock *sk;
2185};
2186
Johan Hedberg72a734e2010-12-30 00:38:22 +02002187static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002188{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002189 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002190 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002191
Johan Hedberg72a734e2010-12-30 00:38:22 +02002192 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002193 return;
2194
Johan Hedberg053f0212011-01-26 13:07:10 +02002195 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002196
2197 list_del(&cmd->list);
2198
2199 if (match->sk == NULL) {
2200 match->sk = cmd->sk;
2201 sock_hold(match->sk);
2202 }
2203
2204 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002205}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002206
2207int mgmt_powered(u16 index, u8 powered)
2208{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002209 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002210 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002211 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002212
Brian Gixa68668b2011-08-11 15:49:36 -07002213 BT_DBG("hci%u %d", index, powered);
2214
Johan Hedberg72a734e2010-12-30 00:38:22 +02002215 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002216
Johan Hedberg72a734e2010-12-30 00:38:22 +02002217 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002218
Szymon Janc4e51eae2011-02-25 19:05:48 +01002219 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002220
2221 if (match.sk)
2222 sock_put(match.sk);
2223
2224 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002225}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002226
Johan Hedberg73f22f62010-12-29 16:00:25 +02002227int mgmt_discoverable(u16 index, u8 discoverable)
2228{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002229 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002230 struct cmd_lookup match = { discoverable, NULL };
2231 int ret;
2232
Szymon Jancb8534e02011-03-01 16:55:34 +01002233 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002234
Johan Hedberg72a734e2010-12-30 00:38:22 +02002235 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002236
Szymon Janc4e51eae2011-02-25 19:05:48 +01002237 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2238 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002239
2240 if (match.sk)
2241 sock_put(match.sk);
2242
2243 return ret;
2244}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002245
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002246int mgmt_connectable(u16 index, u8 connectable)
2247{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002248 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002249 struct cmd_lookup match = { connectable, NULL };
2250 int ret;
2251
Johan Hedberg72a734e2010-12-30 00:38:22 +02002252 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002253
Johan Hedberg72a734e2010-12-30 00:38:22 +02002254 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002255
Szymon Janc4e51eae2011-02-25 19:05:48 +01002256 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002257
2258 if (match.sk)
2259 sock_put(match.sk);
2260
2261 return ret;
2262}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002263
Brian Gixa68668b2011-08-11 15:49:36 -07002264int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002265{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002266 struct mgmt_ev_new_key *ev;
2267 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002268
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002269 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2270 ev = kzalloc(total, GFP_ATOMIC);
2271 if (!ev)
2272 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002273
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002274 bacpy(&ev->key.bdaddr, &key->bdaddr);
2275 ev->key.type = key->type;
2276 memcpy(ev->key.val, key->val, 16);
2277 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002278 ev->key.auth = key->auth;
2279 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002280 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002281
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002282 memcpy(ev->key.data, key->data, key->dlen);
2283
2284 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2285
2286 kfree(ev);
2287
2288 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002289}
Johan Hedbergf7520542011-01-20 12:34:39 +02002290
2291int mgmt_connected(u16 index, bdaddr_t *bdaddr)
2292{
2293 struct mgmt_ev_connected ev;
2294
Johan Hedbergf7520542011-01-20 12:34:39 +02002295 bacpy(&ev.bdaddr, bdaddr);
2296
Szymon Janc4e51eae2011-02-25 19:05:48 +01002297 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002298}
2299
Johan Hedberg8962ee72011-01-20 12:40:27 +02002300static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2301{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002302 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002303 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002304 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002305
Johan Hedberga38528f2011-01-22 06:46:43 +02002306 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002307
Szymon Janc4e51eae2011-02-25 19:05:48 +01002308 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002309
2310 *sk = cmd->sk;
2311 sock_hold(*sk);
2312
Johan Hedberga664b5b2011-02-19 12:06:02 -03002313 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002314}
2315
Johan Hedbergf7520542011-01-20 12:34:39 +02002316int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2317{
2318 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002319 struct sock *sk = NULL;
2320 int err;
2321
2322 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002323
Johan Hedbergf7520542011-01-20 12:34:39 +02002324 bacpy(&ev.bdaddr, bdaddr);
2325
Szymon Janc4e51eae2011-02-25 19:05:48 +01002326 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002327
2328 if (sk)
2329 sock_put(sk);
2330
2331 return err;
2332}
2333
2334int mgmt_disconnect_failed(u16 index)
2335{
2336 struct pending_cmd *cmd;
2337 int err;
2338
2339 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2340 if (!cmd)
2341 return -ENOENT;
2342
Szymon Janc4e51eae2011-02-25 19:05:48 +01002343 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002344
Johan Hedberga664b5b2011-02-19 12:06:02 -03002345 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002346
2347 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002348}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002349
2350int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2351{
2352 struct mgmt_ev_connect_failed ev;
2353
Johan Hedberg17d5c042011-01-22 06:09:08 +02002354 bacpy(&ev.bdaddr, bdaddr);
2355 ev.status = status;
2356
Szymon Janc4e51eae2011-02-25 19:05:48 +01002357 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002358}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002361{
2362 struct mgmt_ev_pin_code_request ev;
2363
Brian Gixa68668b2011-08-11 15:49:36 -07002364 BT_DBG("hci%u", index);
2365
Johan Hedberg980e1a52011-01-22 06:10:07 +02002366 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002367 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002368
Szymon Janc4e51eae2011-02-25 19:05:48 +01002369 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2370 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002371}
2372
2373int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2374{
2375 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002376 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002377 int err;
2378
2379 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2380 if (!cmd)
2381 return -ENOENT;
2382
Johan Hedbergac56fb12011-02-19 12:05:59 -03002383 bacpy(&rp.bdaddr, bdaddr);
2384 rp.status = status;
2385
Szymon Janc4e51eae2011-02-25 19:05:48 +01002386 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2387 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002388
Johan Hedberga664b5b2011-02-19 12:06:02 -03002389 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002390
2391 return err;
2392}
2393
2394int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2395{
2396 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002397 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002398 int err;
2399
2400 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2401 if (!cmd)
2402 return -ENOENT;
2403
Johan Hedbergac56fb12011-02-19 12:05:59 -03002404 bacpy(&rp.bdaddr, bdaddr);
2405 rp.status = status;
2406
Szymon Janc4e51eae2011-02-25 19:05:48 +01002407 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2408 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002409
Johan Hedberga664b5b2011-02-19 12:06:02 -03002410 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002411
2412 return err;
2413}
Johan Hedberga5c29682011-02-19 12:05:57 -03002414
Brian Gixa68668b2011-08-11 15:49:36 -07002415int mgmt_user_confirm_request(u16 index, u8 event,
2416 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002417{
2418 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002419 struct hci_conn *conn = NULL;
2420 struct hci_dev *hdev;
2421 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2422
2423 BT_DBG("hci%u", index);
2424
2425 hdev = hci_dev_get(index);
2426
Brian Gix64bd5302011-09-08 11:35:48 -07002427 if (!hdev)
2428 return -ENODEV;
2429
2430 hci_dev_lock(hdev);
2431
2432 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002433
2434 ev.auto_confirm = 0;
2435
2436 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2437 goto no_auto_confirm;
2438
2439 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2440 rem_cap = conn->remote_cap;
2441 loc_mitm = conn->auth_type & 0x01;
2442 rem_mitm = conn->remote_auth & 0x01;
2443
2444 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2445 goto no_auto_confirm;
2446
2447
2448 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2449 ev.auto_confirm = 1;
2450
2451no_auto_confirm:
2452 bacpy(&ev.bdaddr, bdaddr);
2453 ev.event = event;
2454 put_unaligned_le32(value, &ev.value);
2455
Brian Gix64bd5302011-09-08 11:35:48 -07002456 hci_dev_unlock(hdev);
2457 hci_dev_put(hdev);
2458
Brian Gixa68668b2011-08-11 15:49:36 -07002459 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2460 NULL);
2461}
2462
2463int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2464{
2465 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002466
2467 BT_DBG("hci%u", index);
2468
Johan Hedberga5c29682011-02-19 12:05:57 -03002469 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002470
Brian Gixa68668b2011-08-11 15:49:36 -07002471 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002472 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002473}
2474
2475static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2476 u8 opcode)
2477{
2478 struct pending_cmd *cmd;
2479 struct mgmt_rp_user_confirm_reply rp;
2480 int err;
2481
2482 cmd = mgmt_pending_find(opcode, index);
2483 if (!cmd)
2484 return -ENOENT;
2485
Johan Hedberga5c29682011-02-19 12:05:57 -03002486 bacpy(&rp.bdaddr, bdaddr);
2487 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002488 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002489
Johan Hedberga664b5b2011-02-19 12:06:02 -03002490 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002491
2492 return err;
2493}
2494
2495int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2496{
2497 return confirm_reply_complete(index, bdaddr, status,
2498 MGMT_OP_USER_CONFIRM_REPLY);
2499}
2500
Szymon Jancb8534e02011-03-01 16:55:34 +01002501int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002502{
2503 return confirm_reply_complete(index, bdaddr, status,
2504 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2505}
Johan Hedberg2a611692011-02-19 12:06:00 -03002506
2507int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2508{
2509 struct mgmt_ev_auth_failed ev;
2510
Johan Hedberg2a611692011-02-19 12:06:00 -03002511 bacpy(&ev.bdaddr, bdaddr);
2512 ev.status = status;
2513
Szymon Janc4e51eae2011-02-25 19:05:48 +01002514 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002515}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002516
2517int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2518{
2519 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002520 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002521 struct mgmt_cp_set_local_name ev;
2522 int err;
2523
2524 memset(&ev, 0, sizeof(ev));
2525 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2526
2527 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2528 if (!cmd)
2529 goto send_event;
2530
2531 if (status) {
2532 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2533 goto failed;
2534 }
2535
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002536 hdev = hci_dev_get(index);
2537 if (hdev) {
2538 hci_dev_lock_bh(hdev);
2539 update_eir(hdev);
2540 hci_dev_unlock_bh(hdev);
2541 hci_dev_put(hdev);
2542 }
2543
Johan Hedbergb312b1612011-03-16 14:29:37 +02002544 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2545 sizeof(ev));
2546 if (err < 0)
2547 goto failed;
2548
2549send_event:
2550 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2551 cmd ? cmd->sk : NULL);
2552
2553failed:
2554 if (cmd)
2555 mgmt_pending_remove(cmd);
2556 return err;
2557}
Szymon Jancc35938b2011-03-22 13:12:21 +01002558
2559int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2560 u8 status)
2561{
2562 struct pending_cmd *cmd;
2563 int err;
2564
2565 BT_DBG("hci%u status %u", index, status);
2566
2567 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2568 if (!cmd)
2569 return -ENOENT;
2570
2571 if (status) {
2572 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2573 EIO);
2574 } else {
2575 struct mgmt_rp_read_local_oob_data rp;
2576
2577 memcpy(rp.hash, hash, sizeof(rp.hash));
2578 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2579
2580 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2581 &rp, sizeof(rp));
2582 }
2583
2584 mgmt_pending_remove(cmd);
2585
2586 return err;
2587}
Johan Hedberge17acd42011-03-30 23:57:16 +03002588
Brian Gixa68668b2011-08-11 15:49:36 -07002589int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2590 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002591{
2592 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002593 struct pending_cmd *cmd;
2594 int err;
2595
2596 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002597
2598 memset(&ev, 0, sizeof(ev));
2599
2600 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002601 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002602 ev.type = type;
2603 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002604
Brian Gixa68668b2011-08-11 15:49:36 -07002605 if (dev_class)
2606 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002607
Brian Gixa68668b2011-08-11 15:49:36 -07002608 if (eir && eir_len)
2609 memcpy(ev.eir, eir, eir_len);
2610
2611 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2612
2613 if (err < 0)
2614 return err;
2615
2616 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2617 if (cmd) {
2618 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002619 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002620
2621 ilp->int_count++;
2622 if (hdev && ilp->int_count >= ilp->int_phase) {
2623 /* Inquiry scan for General Discovery LAP */
2624 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2625 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002626
2627 hci_dev_lock(hdev);
2628
Brian Gixa68668b2011-08-11 15:49:36 -07002629 ilp->int_phase *= 2;
2630 ilp->int_count = 0;
2631 if (ilp->mode == SCAN_LE) {
2632 /* cancel LE scan */
2633 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2634 sizeof(le_cp), &le_cp);
2635 /* start BR scan */
2636 cp.num_rsp = (u8) ilp->int_phase;
2637 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2638 sizeof(cp), &cp);
2639 ilp->mode = SCAN_BR;
2640 del_timer_sync(&ilp->le_timer);
2641 }
Brian Gix64bd5302011-09-08 11:35:48 -07002642 hci_dev_unlock(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002643 }
Brian Gix64bd5302011-09-08 11:35:48 -07002644
2645 if (hdev)
2646 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002647 }
2648
2649 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002650}
Johan Hedberga88a9652011-03-30 13:18:12 +03002651
Brian Gixa68668b2011-08-11 15:49:36 -07002652
2653int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002654{
2655 struct mgmt_ev_remote_name ev;
2656
2657 memset(&ev, 0, sizeof(ev));
2658
2659 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002660 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002661 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2662
2663 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2664}