blob: 354207d3189337a3871a5e8b7c095f6bcd2fc856 [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
Johan Hedberga664b5b2011-02-19 12:06:02 -03001339 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340}
1341
1342static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1343{
1344 struct pending_cmd *cmd;
1345
Brian Gixa68668b2011-08-11 15:49:36 -07001346 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347
1348 cmd = find_pairing(conn);
1349 if (!cmd) {
1350 BT_DBG("Unable to find a pending command");
1351 return;
1352 }
1353
1354 pairing_complete(cmd, status);
1355}
1356
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001357static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001358{
1359 struct pending_cmd *cmd;
1360
1361 BT_DBG(" %u", status);
1362
1363 cmd = find_pairing(conn);
1364 if (!cmd) {
1365 BT_DBG("Unable to find a pending command");
1366 return;
1367 }
1368
1369 if (conn->type == LE_LINK)
1370 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1371 status ? 0 : 1);
1372 else
1373 pairing_complete(cmd, status);
1374}
1375
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001376static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001377{
1378 struct pending_cmd *cmd;
1379
1380 BT_DBG("conn: %p %u", conn, status);
1381
1382 cmd = find_pairing(conn);
1383 if (!cmd) {
1384 BT_DBG("Unable to find a pending command");
1385 return;
1386 }
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001387 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001388}
1389
1390static void discovery_terminated(struct pending_cmd *cmd, void *data)
1391{
1392 struct mgmt_mode ev = {0};
1393 struct disco_interleave *ilp = cmd->param;
1394
1395 BT_DBG("");
1396 del_timer_sync(&ilp->le_timer);
1397 del_timer_sync(&ilp->timer);
1398 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1399
1400 list_del(&cmd->list);
1401
1402 mgmt_pending_free(cmd);
1403}
1404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001406{
1407 struct hci_dev *hdev;
1408 struct mgmt_cp_pair_device *cp;
1409 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001410 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001411 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001412 int err;
1413
1414 BT_DBG("");
1415
Brian Gix64bd5302011-09-08 11:35:48 -07001416 cp = (void *) data;
1417
1418 if (len != sizeof(*cp))
1419 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1420
Szymon Janc4e51eae2011-02-25 19:05:48 +01001421 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001422
Johan Hedberge9a416b2011-02-19 12:05:56 -03001423 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001427
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301428 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1429 io_cap = cp->io_cap;
1430 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001431 sec_level = BT_SECURITY_MEDIUM;
1432 auth_type = HCI_AT_DEDICATED_BONDING;
1433 } else {
1434 sec_level = BT_SECURITY_HIGH;
1435 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1436 }
1437
Brian Gixa68668b2011-08-11 15:49:36 -07001438 if (hci_find_adv_entry(hdev, &cp->bdaddr)) {
1439 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1440 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001441 } else {
1442 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1443 if (io_cap == 0x04)
1444 io_cap = 0x01;
1445 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1446 auth_type);
1447 }
1448
Ville Tervo30e76272011-02-22 16:10:53 -03001449 if (IS_ERR(conn)) {
1450 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001451 goto unlock;
1452 }
1453
1454 if (conn->connect_cfm_cb) {
1455 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001456 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001457 goto unlock;
1458 }
1459
Szymon Janc4e51eae2011-02-25 19:05:48 +01001460 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001461 if (!cmd) {
1462 err = -ENOMEM;
1463 hci_conn_put(conn);
1464 goto unlock;
1465 }
1466
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001467 conn->connect_cfm_cb = pairing_connect_complete_cb;
1468 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001469 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001470 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001471 cmd->user_data = conn;
1472
1473 if (conn->state == BT_CONNECTED &&
1474 hci_conn_security(conn, sec_level, auth_type))
1475 pairing_complete(cmd, 0);
1476
1477 err = 0;
1478
1479unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001481 hci_dev_put(hdev);
1482
1483 return err;
1484}
1485
Szymon Janc4e51eae2011-02-25 19:05:48 +01001486static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001487 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001488{
1489 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001490 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001491 struct pending_cmd *cmd;
1492 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001493 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001494 int err;
1495
Brian Gixa68668b2011-08-11 15:49:36 -07001496 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001497
Brian Gixa68668b2011-08-11 15:49:36 -07001498 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001499 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001500 else
1501 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001502
Brian Gixa68668b2011-08-11 15:49:36 -07001503 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001504 return cmd_status(sk, index, mgmt_op, EINVAL);
1505
Szymon Janc4e51eae2011-02-25 19:05:48 +01001506 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001507 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001511
Johan Hedberga5c29682011-02-19 12:05:57 -03001512 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001514 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001515 }
1516
Brian Gixa68668b2011-08-11 15:49:36 -07001517 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1518 if (le_conn) {
1519 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1520 goto done;
1521 }
1522 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1523 "Reject" : "Accept");
1524
Szymon Janc4e51eae2011-02-25 19:05:48 +01001525 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001526 if (!cmd) {
1527 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001528 goto done;
1529 }
1530
1531 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1532 if (err < 0)
1533 mgmt_pending_remove(cmd);
1534
1535done:
1536 hci_dev_unlock(hdev);
1537 hci_dev_put(hdev);
1538
1539 return err;
1540}
1541
1542static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1543 u16 len)
1544{
1545 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1546 struct hci_cp_remote_name_req hci_cp;
1547 struct hci_dev *hdev;
1548 struct pending_cmd *cmd;
1549 int err;
1550
1551 BT_DBG("");
1552
1553 if (len != sizeof(*mgmt_cp))
1554 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1555
1556 hdev = hci_dev_get(index);
1557 if (!hdev)
1558 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1559
1560 hci_dev_lock(hdev);
1561
1562 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1563 if (!cmd) {
1564 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001565 goto failed;
1566 }
1567
Brian Gixa68668b2011-08-11 15:49:36 -07001568 memset(&hci_cp, 0, sizeof(hci_cp));
1569 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1570 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1571 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001572 if (err < 0)
1573 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001574
1575failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001577 hci_dev_put(hdev);
1578
1579 return err;
1580}
1581
Johan Hedbergb312b1612011-03-16 14:29:37 +02001582static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1583 u16 len)
1584{
1585 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1586 struct hci_cp_write_local_name hci_cp;
1587 struct hci_dev *hdev;
1588 struct pending_cmd *cmd;
1589 int err;
1590
1591 BT_DBG("");
1592
1593 if (len != sizeof(*mgmt_cp))
1594 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1595
1596 hdev = hci_dev_get(index);
1597 if (!hdev)
1598 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001601
1602 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1603 if (!cmd) {
1604 err = -ENOMEM;
1605 goto failed;
1606 }
1607
1608 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1609 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1610 &hci_cp);
1611 if (err < 0)
1612 mgmt_pending_remove(cmd);
1613
1614failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001616 hci_dev_put(hdev);
1617
1618 return err;
1619}
1620
Brian Gixa68668b2011-08-11 15:49:36 -07001621static void discovery_rsp(struct pending_cmd *cmd, void *data)
1622{
1623 struct mgmt_mode ev;
1624
1625 BT_DBG("");
1626 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1627 ev.val = 1;
1628 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1629 } else {
1630 ev.val = 0;
1631 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1632 NULL, 0);
1633 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1634 struct disco_interleave *ilp = cmd->param;
1635
1636 del_timer_sync(&ilp->le_timer);
1637 del_timer_sync(&ilp->timer);
1638 }
1639 }
1640
1641 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1642
1643 list_del(&cmd->list);
1644
1645 mgmt_pending_free(cmd);
1646}
1647
1648void mgmt_inquiry_started(u16 index)
1649{
1650 BT_DBG("");
1651 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1652 discovery_rsp, NULL);
1653}
1654
1655void mgmt_inquiry_complete_evt(u16 index, u8 status)
1656{
1657 struct hci_dev *hdev;
1658 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1659 struct pending_cmd *cmd;
1660 int err = -1;
1661
1662 BT_DBG("");
1663
1664 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001665
1666 if (hdev)
1667 hci_dev_lock(hdev);
1668
Brian Gixa68668b2011-08-11 15:49:36 -07001669 if (!hdev || !lmp_le_capable(hdev)) {
1670 struct mgmt_mode cp = {0};
1671
1672 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1673 discovery_terminated, NULL);
1674
1675 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001676
Brian Gix64bd5302011-09-08 11:35:48 -07001677 if (hdev)
1678 goto done;
1679 else
1680 return;
1681 }
Brian Gixa68668b2011-08-11 15:49:36 -07001682
1683 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1684 if (cmd && cmd->param) {
1685 struct disco_interleave *ilp = cmd->param;
1686
1687 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1688 sizeof(le_cp), &le_cp);
1689 if (err >= 0) {
1690 mod_timer(&ilp->le_timer, jiffies +
1691 msecs_to_jiffies(ilp->int_phase * 1000));
1692 ilp->mode = SCAN_LE;
1693 } else
1694 ilp->mode = SCAN_IDLE;
1695 }
1696
1697 if (err < 0)
1698 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1699 discovery_terminated, NULL);
1700
Brian Gix64bd5302011-09-08 11:35:48 -07001701done:
Brian Gixa68668b2011-08-11 15:49:36 -07001702 hci_dev_unlock(hdev);
1703 hci_dev_put(hdev);
1704}
1705
1706static void disco_to(unsigned long data)
1707{
1708 struct disco_interleave *ilp = (void *)data;
1709 struct hci_dev *hdev;
1710 struct pending_cmd *cmd;
1711
1712 BT_DBG("hci%d", ilp->index);
1713
1714 del_timer_sync(&ilp->le_timer);
1715 hdev = hci_dev_get(ilp->index);
1716
1717 if (hdev) {
1718 hci_dev_lock(hdev);
1719
1720 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1721
1722 if (ilp->mode != SCAN_IDLE) {
1723 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1724
1725 if (ilp->mode == SCAN_LE)
1726 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1727 sizeof(le_cp), &le_cp);
1728 else
1729 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1730 0, NULL);
1731
1732 ilp->mode = SCAN_IDLE;
1733 }
1734
1735 if (cmd) {
1736 struct mgmt_mode cp = {0};
1737
1738 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1739 sizeof(cp), NULL);
1740 mgmt_pending_remove(cmd);
1741 }
1742
1743 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001744 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001745 }
1746}
1747
1748static void disco_le_to(unsigned long data)
1749{
1750 struct disco_interleave *ilp = (void *)data;
1751 struct hci_dev *hdev;
1752 struct pending_cmd *cmd;
1753 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1754
1755 BT_DBG("hci%d", ilp->index);
1756
1757 hdev = hci_dev_get(ilp->index);
1758 del_timer_sync(&ilp->le_timer);
1759
1760 if (hdev) {
1761 hci_dev_lock(hdev);
1762
1763 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1764
1765 if (ilp->mode == SCAN_LE)
1766 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1767 sizeof(le_cp), &le_cp);
1768
1769 /* re-start BR scan */
1770 if (cmd) {
1771 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1772 ilp->int_phase *= 2;
1773 ilp->int_count = 0;
1774 cp.num_rsp = (u8) ilp->int_phase;
1775 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1776 ilp->mode = SCAN_BR;
1777 } else
1778 ilp->mode = SCAN_IDLE;
1779
1780 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001781 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001782 }
1783}
1784
1785static int start_discovery(struct sock *sk, u16 index)
1786{
1787 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1788 struct hci_dev *hdev;
1789 struct pending_cmd *cmd;
1790 int err;
1791
1792 BT_DBG("");
1793
1794 hdev = hci_dev_get(index);
1795 if (!hdev)
1796 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1797
1798 hci_dev_lock(hdev);
1799
1800 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1801 if (!cmd) {
1802 err = -ENOMEM;
1803 goto failed;
1804 }
1805
1806 /* If LE Capable, we will alternate between BR/EDR and LE */
1807 if (lmp_le_capable(hdev)) {
1808 struct hci_cp_le_set_scan_parameters le_cp;
1809
1810 /* Shorten BR scan params */
1811 cp.num_rsp = 1;
1812 cp.length /= 2;
1813
1814 /* Setup LE scan params */
1815 memset(&le_cp, 0, sizeof(le_cp));
1816 le_cp.type = 0x01; /* Active scanning */
1817 /* The recommended value for scan interval and window is
1818 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1819 le_cp.interval = cpu_to_le16(0x0012);
1820 le_cp.window = cpu_to_le16(0x0012);
1821 le_cp.own_bdaddr_type = 0; /* Public address */
1822 le_cp.filter = 0; /* Accept all adv packets */
1823
1824 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1825 sizeof(le_cp), &le_cp);
1826 }
1827
1828 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1829
1830 if (err < 0)
1831 mgmt_pending_remove(cmd);
1832 else if (lmp_le_capable(hdev)) {
1833 struct disco_interleave il, *ilp;
1834
1835 il.int_phase = 1;
1836 il.int_count = 0;
1837 il.index = index;
1838 il.mode = SCAN_BR;
1839 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1840 sizeof(struct disco_interleave));
1841 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1842 if (cmd) {
1843 ilp = cmd->param;
1844 setup_timer(&ilp->le_timer, disco_le_to,
1845 (unsigned long) ilp);
1846 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1847 mod_timer(&ilp->timer,
1848 jiffies + msecs_to_jiffies(20000));
1849 }
1850 }
1851
1852failed:
1853 hci_dev_unlock(hdev);
1854 hci_dev_put(hdev);
1855
1856 return err;
1857}
1858
1859static int stop_discovery(struct sock *sk, u16 index)
1860{
1861 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1862 struct mgmt_mode mode_cp = {0};
1863 struct disco_interleave *ilp = NULL;
1864 struct hci_dev *hdev;
1865 struct pending_cmd *cmd = NULL;
1866 int err = -EPERM;
1867
1868 BT_DBG("");
1869
1870 hdev = hci_dev_get(index);
1871 if (!hdev)
1872 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1873
1874 hci_dev_lock(hdev);
1875
1876 if (lmp_le_capable(hdev)) {
1877 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1878 if (!cmd) {
1879 err = -ENOMEM;
1880 goto failed;
1881 }
1882
1883 ilp = cmd->param;
1884 }
1885
1886 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1887 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1888 sizeof(le_cp), &le_cp);
1889
1890 if (err < 0) {
1891 if (!ilp || (ilp->mode == SCAN_BR))
1892 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1893 0, NULL);
1894 }
1895
1896 if (ilp) {
1897 ilp->mode = SCAN_IDLE;
1898 del_timer_sync(&ilp->le_timer);
1899 del_timer_sync(&ilp->timer);
1900 }
1901
1902 if (err < 0 && cmd)
1903 mgmt_pending_remove(cmd);
1904
1905 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1906
1907failed:
1908 hci_dev_unlock(hdev);
1909 hci_dev_put(hdev);
1910
1911 if (err < 0)
1912 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1913 else
1914 return err;
1915}
1916
Szymon Jancc35938b2011-03-22 13:12:21 +01001917static int read_local_oob_data(struct sock *sk, u16 index)
1918{
1919 struct hci_dev *hdev;
1920 struct pending_cmd *cmd;
1921 int err;
1922
1923 BT_DBG("hci%u", index);
1924
1925 hdev = hci_dev_get(index);
1926 if (!hdev)
1927 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1928 ENODEV);
1929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001931
1932 if (!test_bit(HCI_UP, &hdev->flags)) {
1933 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1934 ENETDOWN);
1935 goto unlock;
1936 }
1937
1938 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1939 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1940 EOPNOTSUPP);
1941 goto unlock;
1942 }
1943
1944 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1945 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1946 goto unlock;
1947 }
1948
1949 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1950 if (!cmd) {
1951 err = -ENOMEM;
1952 goto unlock;
1953 }
1954
1955 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1956 if (err < 0)
1957 mgmt_pending_remove(cmd);
1958
1959unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001961 hci_dev_put(hdev);
1962
1963 return err;
1964}
1965
Szymon Janc2763eda2011-03-22 13:12:22 +01001966static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1967 u16 len)
1968{
1969 struct hci_dev *hdev;
1970 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1971 int err;
1972
1973 BT_DBG("hci%u ", index);
1974
1975 if (len != sizeof(*cp))
1976 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1977 EINVAL);
1978
1979 hdev = hci_dev_get(index);
1980 if (!hdev)
1981 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1982 ENODEV);
1983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001985
1986 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1987 cp->randomizer);
1988 if (err < 0)
1989 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1990 else
1991 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1992 0);
1993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001995 hci_dev_put(hdev);
1996
1997 return err;
1998}
1999
2000static int remove_remote_oob_data(struct sock *sk, u16 index,
2001 unsigned char *data, u16 len)
2002{
2003 struct hci_dev *hdev;
2004 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2005 int err;
2006
2007 BT_DBG("hci%u ", index);
2008
2009 if (len != sizeof(*cp))
2010 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2011 EINVAL);
2012
2013 hdev = hci_dev_get(index);
2014 if (!hdev)
2015 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2016 ENODEV);
2017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002019
2020 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2021 if (err < 0)
2022 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2023 -err);
2024 else
2025 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2026 NULL, 0);
2027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002029 hci_dev_put(hdev);
2030
2031 return err;
2032}
2033
Johan Hedberg03811012010-12-08 00:21:06 +02002034int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2035{
2036 unsigned char *buf;
2037 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002038 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002039 int err;
2040
2041 BT_DBG("got %zu bytes", msglen);
2042
2043 if (msglen < sizeof(*hdr))
2044 return -EINVAL;
2045
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002046 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002047 if (!buf)
2048 return -ENOMEM;
2049
2050 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2051 err = -EFAULT;
2052 goto done;
2053 }
2054
2055 hdr = (struct mgmt_hdr *) buf;
2056 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002057 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002058 len = get_unaligned_le16(&hdr->len);
2059
2060 if (len != msglen - sizeof(*hdr)) {
2061 err = -EINVAL;
2062 goto done;
2063 }
2064
Brian Gixa68668b2011-08-11 15:49:36 -07002065 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002066 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002067 case MGMT_OP_READ_VERSION:
2068 err = read_version(sk);
2069 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002070 case MGMT_OP_READ_INDEX_LIST:
2071 err = read_index_list(sk);
2072 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002073 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002074 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002075 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002076 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002077 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002078 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002079 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002080 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002081 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002082 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002083 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002084 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002085 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002086 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002087 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002089 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090 break;
2091 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002092 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002093 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002094 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002095 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002096 break;
2097 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002098 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002099 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002100 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002101 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002102 break;
2103 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002104 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002105 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002106 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002107 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002108 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002109 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002110 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002111 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002112 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002113 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002114 break;
2115 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002116 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002117 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002118 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002119 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002120 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002121 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002122 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002123 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002124 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002125 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002126 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002127 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2128 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002129 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002130 case MGMT_OP_SET_LOCAL_NAME:
2131 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2132 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002133 case MGMT_OP_START_DISCOVERY:
2134 err = start_discovery(sk, index);
2135 break;
2136 case MGMT_OP_STOP_DISCOVERY:
2137 err = stop_discovery(sk, index);
2138 break;
2139 case MGMT_OP_RESOLVE_NAME:
2140 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2141 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002142 case MGMT_OP_READ_LOCAL_OOB_DATA:
2143 err = read_local_oob_data(sk, index);
2144 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002145 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2146 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2147 break;
2148 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2149 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2150 len);
2151 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152
Johan Hedberg03811012010-12-08 00:21:06 +02002153 default:
2154 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002155 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002156 break;
2157 }
2158
Johan Hedberge41d8b42010-12-13 21:07:03 +02002159 if (err < 0)
2160 goto done;
2161
Johan Hedberg03811012010-12-08 00:21:06 +02002162 err = msglen;
2163
2164done:
2165 kfree(buf);
2166 return err;
2167}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002168
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002169int mgmt_index_added(u16 index)
2170{
Brian Gixa68668b2011-08-11 15:49:36 -07002171 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002172 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002173}
2174
2175int mgmt_index_removed(u16 index)
2176{
Brian Gixa68668b2011-08-11 15:49:36 -07002177 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002178 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002179}
2180
Johan Hedberg73f22f62010-12-29 16:00:25 +02002181struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002182 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002183 struct sock *sk;
2184};
2185
Johan Hedberg72a734e2010-12-30 00:38:22 +02002186static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002187{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002188 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002189 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002190
Johan Hedberg72a734e2010-12-30 00:38:22 +02002191 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002192 return;
2193
Johan Hedberg053f0212011-01-26 13:07:10 +02002194 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002195
2196 list_del(&cmd->list);
2197
2198 if (match->sk == NULL) {
2199 match->sk = cmd->sk;
2200 sock_hold(match->sk);
2201 }
2202
2203 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002204}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002205
2206int mgmt_powered(u16 index, u8 powered)
2207{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002208 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002209 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002210 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002211
Brian Gixa68668b2011-08-11 15:49:36 -07002212 BT_DBG("hci%u %d", index, powered);
2213
Johan Hedberg72a734e2010-12-30 00:38:22 +02002214 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002215
Johan Hedberg72a734e2010-12-30 00:38:22 +02002216 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002217
Szymon Janc4e51eae2011-02-25 19:05:48 +01002218 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002219
2220 if (match.sk)
2221 sock_put(match.sk);
2222
2223 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002224}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002225
Johan Hedberg73f22f62010-12-29 16:00:25 +02002226int mgmt_discoverable(u16 index, u8 discoverable)
2227{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002228 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002229 struct cmd_lookup match = { discoverable, NULL };
2230 int ret;
2231
Szymon Jancb8534e02011-03-01 16:55:34 +01002232 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002233
Johan Hedberg72a734e2010-12-30 00:38:22 +02002234 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002235
Szymon Janc4e51eae2011-02-25 19:05:48 +01002236 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2237 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002238
2239 if (match.sk)
2240 sock_put(match.sk);
2241
2242 return ret;
2243}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002244
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002245int mgmt_connectable(u16 index, u8 connectable)
2246{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002247 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002248 struct cmd_lookup match = { connectable, NULL };
2249 int ret;
2250
Johan Hedberg72a734e2010-12-30 00:38:22 +02002251 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002252
Johan Hedberg72a734e2010-12-30 00:38:22 +02002253 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002254
Szymon Janc4e51eae2011-02-25 19:05:48 +01002255 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002256
2257 if (match.sk)
2258 sock_put(match.sk);
2259
2260 return ret;
2261}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002262
Brian Gixa68668b2011-08-11 15:49:36 -07002263int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002264{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002265 struct mgmt_ev_new_key *ev;
2266 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002267
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002268 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2269 ev = kzalloc(total, GFP_ATOMIC);
2270 if (!ev)
2271 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002272
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002273 bacpy(&ev->key.bdaddr, &key->bdaddr);
2274 ev->key.type = key->type;
2275 memcpy(ev->key.val, key->val, 16);
2276 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002277 ev->key.auth = key->auth;
2278 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002279 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002280
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002281 memcpy(ev->key.data, key->data, key->dlen);
2282
2283 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2284
2285 kfree(ev);
2286
2287 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002288}
Johan Hedbergf7520542011-01-20 12:34:39 +02002289
2290int mgmt_connected(u16 index, bdaddr_t *bdaddr)
2291{
2292 struct mgmt_ev_connected ev;
2293
Johan Hedbergf7520542011-01-20 12:34:39 +02002294 bacpy(&ev.bdaddr, bdaddr);
2295
Szymon Janc4e51eae2011-02-25 19:05:48 +01002296 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002297}
2298
Johan Hedberg8962ee72011-01-20 12:40:27 +02002299static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2300{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002301 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002302 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002303 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304
Johan Hedberga38528f2011-01-22 06:46:43 +02002305 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002306
Szymon Janc4e51eae2011-02-25 19:05:48 +01002307 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002308
2309 *sk = cmd->sk;
2310 sock_hold(*sk);
2311
Johan Hedberga664b5b2011-02-19 12:06:02 -03002312 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002313}
2314
Johan Hedbergf7520542011-01-20 12:34:39 +02002315int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2316{
2317 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002318 struct sock *sk = NULL;
2319 int err;
2320
2321 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002322
Johan Hedbergf7520542011-01-20 12:34:39 +02002323 bacpy(&ev.bdaddr, bdaddr);
2324
Szymon Janc4e51eae2011-02-25 19:05:48 +01002325 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002326
2327 if (sk)
2328 sock_put(sk);
2329
2330 return err;
2331}
2332
2333int mgmt_disconnect_failed(u16 index)
2334{
2335 struct pending_cmd *cmd;
2336 int err;
2337
2338 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2339 if (!cmd)
2340 return -ENOENT;
2341
Szymon Janc4e51eae2011-02-25 19:05:48 +01002342 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002343
Johan Hedberga664b5b2011-02-19 12:06:02 -03002344 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002345
2346 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002347}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002348
2349int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2350{
2351 struct mgmt_ev_connect_failed ev;
2352
Johan Hedberg17d5c042011-01-22 06:09:08 +02002353 bacpy(&ev.bdaddr, bdaddr);
2354 ev.status = status;
2355
Szymon Janc4e51eae2011-02-25 19:05:48 +01002356 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002357}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002360{
2361 struct mgmt_ev_pin_code_request ev;
2362
Brian Gixa68668b2011-08-11 15:49:36 -07002363 BT_DBG("hci%u", index);
2364
Johan Hedberg980e1a52011-01-22 06:10:07 +02002365 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002366 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002367
Szymon Janc4e51eae2011-02-25 19:05:48 +01002368 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2369 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002370}
2371
2372int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2373{
2374 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002375 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002376 int err;
2377
2378 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2379 if (!cmd)
2380 return -ENOENT;
2381
Johan Hedbergac56fb12011-02-19 12:05:59 -03002382 bacpy(&rp.bdaddr, bdaddr);
2383 rp.status = status;
2384
Szymon Janc4e51eae2011-02-25 19:05:48 +01002385 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2386 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387
Johan Hedberga664b5b2011-02-19 12:06:02 -03002388 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002389
2390 return err;
2391}
2392
2393int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2394{
2395 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002396 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002397 int err;
2398
2399 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2400 if (!cmd)
2401 return -ENOENT;
2402
Johan Hedbergac56fb12011-02-19 12:05:59 -03002403 bacpy(&rp.bdaddr, bdaddr);
2404 rp.status = status;
2405
Szymon Janc4e51eae2011-02-25 19:05:48 +01002406 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2407 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002408
Johan Hedberga664b5b2011-02-19 12:06:02 -03002409 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002410
2411 return err;
2412}
Johan Hedberga5c29682011-02-19 12:05:57 -03002413
Brian Gixa68668b2011-08-11 15:49:36 -07002414int mgmt_user_confirm_request(u16 index, u8 event,
2415 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002416{
2417 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002418 struct hci_conn *conn = NULL;
2419 struct hci_dev *hdev;
2420 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2421
2422 BT_DBG("hci%u", index);
2423
2424 hdev = hci_dev_get(index);
2425
Brian Gix64bd5302011-09-08 11:35:48 -07002426 if (!hdev)
2427 return -ENODEV;
2428
2429 hci_dev_lock(hdev);
2430
2431 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002432
2433 ev.auto_confirm = 0;
2434
2435 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2436 goto no_auto_confirm;
2437
2438 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2439 rem_cap = conn->remote_cap;
2440 loc_mitm = conn->auth_type & 0x01;
2441 rem_mitm = conn->remote_auth & 0x01;
2442
2443 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2444 goto no_auto_confirm;
2445
2446
2447 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2448 ev.auto_confirm = 1;
2449
2450no_auto_confirm:
2451 bacpy(&ev.bdaddr, bdaddr);
2452 ev.event = event;
2453 put_unaligned_le32(value, &ev.value);
2454
Brian Gix64bd5302011-09-08 11:35:48 -07002455 hci_dev_unlock(hdev);
2456 hci_dev_put(hdev);
2457
Brian Gixa68668b2011-08-11 15:49:36 -07002458 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2459 NULL);
2460}
2461
2462int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2463{
2464 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002465
2466 BT_DBG("hci%u", index);
2467
Johan Hedberga5c29682011-02-19 12:05:57 -03002468 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002469
Brian Gixa68668b2011-08-11 15:49:36 -07002470 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002471 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002472}
2473
2474static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2475 u8 opcode)
2476{
2477 struct pending_cmd *cmd;
2478 struct mgmt_rp_user_confirm_reply rp;
2479 int err;
2480
2481 cmd = mgmt_pending_find(opcode, index);
2482 if (!cmd)
2483 return -ENOENT;
2484
Johan Hedberga5c29682011-02-19 12:05:57 -03002485 bacpy(&rp.bdaddr, bdaddr);
2486 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002487 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002488
Johan Hedberga664b5b2011-02-19 12:06:02 -03002489 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002490
2491 return err;
2492}
2493
2494int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2495{
2496 return confirm_reply_complete(index, bdaddr, status,
2497 MGMT_OP_USER_CONFIRM_REPLY);
2498}
2499
Szymon Jancb8534e02011-03-01 16:55:34 +01002500int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002501{
2502 return confirm_reply_complete(index, bdaddr, status,
2503 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2504}
Johan Hedberg2a611692011-02-19 12:06:00 -03002505
2506int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2507{
2508 struct mgmt_ev_auth_failed ev;
2509
Johan Hedberg2a611692011-02-19 12:06:00 -03002510 bacpy(&ev.bdaddr, bdaddr);
2511 ev.status = status;
2512
Szymon Janc4e51eae2011-02-25 19:05:48 +01002513 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002514}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002515
2516int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2517{
2518 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002519 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002520 struct mgmt_cp_set_local_name ev;
2521 int err;
2522
2523 memset(&ev, 0, sizeof(ev));
2524 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2525
2526 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2527 if (!cmd)
2528 goto send_event;
2529
2530 if (status) {
2531 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2532 goto failed;
2533 }
2534
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002535 hdev = hci_dev_get(index);
2536 if (hdev) {
2537 hci_dev_lock_bh(hdev);
2538 update_eir(hdev);
2539 hci_dev_unlock_bh(hdev);
2540 hci_dev_put(hdev);
2541 }
2542
Johan Hedbergb312b1612011-03-16 14:29:37 +02002543 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2544 sizeof(ev));
2545 if (err < 0)
2546 goto failed;
2547
2548send_event:
2549 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2550 cmd ? cmd->sk : NULL);
2551
2552failed:
2553 if (cmd)
2554 mgmt_pending_remove(cmd);
2555 return err;
2556}
Szymon Jancc35938b2011-03-22 13:12:21 +01002557
2558int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2559 u8 status)
2560{
2561 struct pending_cmd *cmd;
2562 int err;
2563
2564 BT_DBG("hci%u status %u", index, status);
2565
2566 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2567 if (!cmd)
2568 return -ENOENT;
2569
2570 if (status) {
2571 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2572 EIO);
2573 } else {
2574 struct mgmt_rp_read_local_oob_data rp;
2575
2576 memcpy(rp.hash, hash, sizeof(rp.hash));
2577 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2578
2579 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2580 &rp, sizeof(rp));
2581 }
2582
2583 mgmt_pending_remove(cmd);
2584
2585 return err;
2586}
Johan Hedberge17acd42011-03-30 23:57:16 +03002587
Brian Gixa68668b2011-08-11 15:49:36 -07002588int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2589 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002590{
2591 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002592 struct pending_cmd *cmd;
2593 int err;
2594
2595 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002596
2597 memset(&ev, 0, sizeof(ev));
2598
2599 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002600 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002601 ev.type = type;
2602 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002603
Brian Gixa68668b2011-08-11 15:49:36 -07002604 if (dev_class)
2605 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002606
Brian Gixa68668b2011-08-11 15:49:36 -07002607 if (eir && eir_len)
2608 memcpy(ev.eir, eir, eir_len);
2609
2610 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2611
2612 if (err < 0)
2613 return err;
2614
2615 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2616 if (cmd) {
2617 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002618 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002619
2620 ilp->int_count++;
2621 if (hdev && ilp->int_count >= ilp->int_phase) {
2622 /* Inquiry scan for General Discovery LAP */
2623 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2624 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002625
2626 hci_dev_lock(hdev);
2627
Brian Gixa68668b2011-08-11 15:49:36 -07002628 ilp->int_phase *= 2;
2629 ilp->int_count = 0;
2630 if (ilp->mode == SCAN_LE) {
2631 /* cancel LE scan */
2632 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2633 sizeof(le_cp), &le_cp);
2634 /* start BR scan */
2635 cp.num_rsp = (u8) ilp->int_phase;
2636 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2637 sizeof(cp), &cp);
2638 ilp->mode = SCAN_BR;
2639 del_timer_sync(&ilp->le_timer);
2640 }
Brian Gix64bd5302011-09-08 11:35:48 -07002641 hci_dev_unlock(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002642 }
Brian Gix64bd5302011-09-08 11:35:48 -07002643
2644 if (hdev)
2645 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002646 }
2647
2648 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002649}
Johan Hedberga88a9652011-03-30 13:18:12 +03002650
Brian Gixa68668b2011-08-11 15:49:36 -07002651
2652int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002653{
2654 struct mgmt_ev_remote_name ev;
2655
2656 memset(&ev, 0, sizeof(ev));
2657
2658 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002659 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002660 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2661
2662 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2663}