blob: 79e0891ea930a123338033e8939806c8039a1dd9 [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);
Brian Gixa68668b2011-08-11 15:49:36 -07001758
1759 if (hdev) {
1760 hci_dev_lock(hdev);
1761
1762 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1763
1764 if (ilp->mode == SCAN_LE)
1765 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1766 sizeof(le_cp), &le_cp);
1767
1768 /* re-start BR scan */
1769 if (cmd) {
1770 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1771 ilp->int_phase *= 2;
1772 ilp->int_count = 0;
1773 cp.num_rsp = (u8) ilp->int_phase;
1774 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1775 ilp->mode = SCAN_BR;
1776 } else
1777 ilp->mode = SCAN_IDLE;
1778
1779 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001780 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001781 }
1782}
1783
1784static int start_discovery(struct sock *sk, u16 index)
1785{
1786 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1787 struct hci_dev *hdev;
1788 struct pending_cmd *cmd;
1789 int err;
1790
1791 BT_DBG("");
1792
1793 hdev = hci_dev_get(index);
1794 if (!hdev)
1795 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1796
1797 hci_dev_lock(hdev);
1798
1799 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1800 if (!cmd) {
1801 err = -ENOMEM;
1802 goto failed;
1803 }
1804
1805 /* If LE Capable, we will alternate between BR/EDR and LE */
1806 if (lmp_le_capable(hdev)) {
1807 struct hci_cp_le_set_scan_parameters le_cp;
1808
1809 /* Shorten BR scan params */
1810 cp.num_rsp = 1;
1811 cp.length /= 2;
1812
1813 /* Setup LE scan params */
1814 memset(&le_cp, 0, sizeof(le_cp));
1815 le_cp.type = 0x01; /* Active scanning */
1816 /* The recommended value for scan interval and window is
1817 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1818 le_cp.interval = cpu_to_le16(0x0012);
1819 le_cp.window = cpu_to_le16(0x0012);
1820 le_cp.own_bdaddr_type = 0; /* Public address */
1821 le_cp.filter = 0; /* Accept all adv packets */
1822
1823 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1824 sizeof(le_cp), &le_cp);
1825 }
1826
1827 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1828
1829 if (err < 0)
1830 mgmt_pending_remove(cmd);
1831 else if (lmp_le_capable(hdev)) {
1832 struct disco_interleave il, *ilp;
1833
1834 il.int_phase = 1;
1835 il.int_count = 0;
1836 il.index = index;
1837 il.mode = SCAN_BR;
1838 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1839 sizeof(struct disco_interleave));
1840 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1841 if (cmd) {
1842 ilp = cmd->param;
1843 setup_timer(&ilp->le_timer, disco_le_to,
1844 (unsigned long) ilp);
1845 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1846 mod_timer(&ilp->timer,
1847 jiffies + msecs_to_jiffies(20000));
1848 }
1849 }
1850
1851failed:
1852 hci_dev_unlock(hdev);
1853 hci_dev_put(hdev);
1854
1855 return err;
1856}
1857
1858static int stop_discovery(struct sock *sk, u16 index)
1859{
1860 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1861 struct mgmt_mode mode_cp = {0};
1862 struct disco_interleave *ilp = NULL;
1863 struct hci_dev *hdev;
1864 struct pending_cmd *cmd = NULL;
1865 int err = -EPERM;
1866
1867 BT_DBG("");
1868
1869 hdev = hci_dev_get(index);
1870 if (!hdev)
1871 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1872
1873 hci_dev_lock(hdev);
1874
1875 if (lmp_le_capable(hdev)) {
1876 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1877 if (!cmd) {
1878 err = -ENOMEM;
1879 goto failed;
1880 }
1881
1882 ilp = cmd->param;
1883 }
1884
1885 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
1886 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1887 sizeof(le_cp), &le_cp);
1888
1889 if (err < 0) {
1890 if (!ilp || (ilp->mode == SCAN_BR))
1891 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1892 0, NULL);
1893 }
1894
1895 if (ilp) {
1896 ilp->mode = SCAN_IDLE;
1897 del_timer_sync(&ilp->le_timer);
1898 del_timer_sync(&ilp->timer);
1899 }
1900
1901 if (err < 0 && cmd)
1902 mgmt_pending_remove(cmd);
1903
1904 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
1905
1906failed:
1907 hci_dev_unlock(hdev);
1908 hci_dev_put(hdev);
1909
1910 if (err < 0)
1911 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
1912 else
1913 return err;
1914}
1915
Szymon Jancc35938b2011-03-22 13:12:21 +01001916static int read_local_oob_data(struct sock *sk, u16 index)
1917{
1918 struct hci_dev *hdev;
1919 struct pending_cmd *cmd;
1920 int err;
1921
1922 BT_DBG("hci%u", index);
1923
1924 hdev = hci_dev_get(index);
1925 if (!hdev)
1926 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1927 ENODEV);
1928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001930
1931 if (!test_bit(HCI_UP, &hdev->flags)) {
1932 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1933 ENETDOWN);
1934 goto unlock;
1935 }
1936
1937 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1938 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1939 EOPNOTSUPP);
1940 goto unlock;
1941 }
1942
1943 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1944 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1945 goto unlock;
1946 }
1947
1948 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1949 if (!cmd) {
1950 err = -ENOMEM;
1951 goto unlock;
1952 }
1953
1954 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1955 if (err < 0)
1956 mgmt_pending_remove(cmd);
1957
1958unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001960 hci_dev_put(hdev);
1961
1962 return err;
1963}
1964
Szymon Janc2763eda2011-03-22 13:12:22 +01001965static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1966 u16 len)
1967{
1968 struct hci_dev *hdev;
1969 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1970 int err;
1971
1972 BT_DBG("hci%u ", index);
1973
1974 if (len != sizeof(*cp))
1975 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1976 EINVAL);
1977
1978 hdev = hci_dev_get(index);
1979 if (!hdev)
1980 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1981 ENODEV);
1982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001984
1985 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1986 cp->randomizer);
1987 if (err < 0)
1988 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1989 else
1990 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1991 0);
1992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001994 hci_dev_put(hdev);
1995
1996 return err;
1997}
1998
1999static int remove_remote_oob_data(struct sock *sk, u16 index,
2000 unsigned char *data, u16 len)
2001{
2002 struct hci_dev *hdev;
2003 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2004 int err;
2005
2006 BT_DBG("hci%u ", index);
2007
2008 if (len != sizeof(*cp))
2009 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2010 EINVAL);
2011
2012 hdev = hci_dev_get(index);
2013 if (!hdev)
2014 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2015 ENODEV);
2016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002018
2019 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2020 if (err < 0)
2021 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2022 -err);
2023 else
2024 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2025 NULL, 0);
2026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002028 hci_dev_put(hdev);
2029
2030 return err;
2031}
2032
Johan Hedberg03811012010-12-08 00:21:06 +02002033int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2034{
2035 unsigned char *buf;
2036 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002037 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002038 int err;
2039
2040 BT_DBG("got %zu bytes", msglen);
2041
2042 if (msglen < sizeof(*hdr))
2043 return -EINVAL;
2044
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002045 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002046 if (!buf)
2047 return -ENOMEM;
2048
2049 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2050 err = -EFAULT;
2051 goto done;
2052 }
2053
2054 hdr = (struct mgmt_hdr *) buf;
2055 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002056 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002057 len = get_unaligned_le16(&hdr->len);
2058
2059 if (len != msglen - sizeof(*hdr)) {
2060 err = -EINVAL;
2061 goto done;
2062 }
2063
Brian Gixa68668b2011-08-11 15:49:36 -07002064 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002065 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002066 case MGMT_OP_READ_VERSION:
2067 err = read_version(sk);
2068 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002069 case MGMT_OP_READ_INDEX_LIST:
2070 err = read_index_list(sk);
2071 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002072 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002073 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002074 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002075 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002076 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002077 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002078 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002079 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002080 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002081 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002082 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002083 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002084 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002085 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002086 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002087 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002088 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 break;
2090 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002091 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002092 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002093 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002094 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002095 break;
2096 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002097 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002098 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002099 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002100 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002101 break;
2102 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002104 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002105 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002106 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002107 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002108 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002109 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002111 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002113 break;
2114 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002116 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002117 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002118 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002119 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002120 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002122 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002123 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002124 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002125 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002126 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2127 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002128 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002129 case MGMT_OP_SET_LOCAL_NAME:
2130 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2131 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002132 case MGMT_OP_START_DISCOVERY:
2133 err = start_discovery(sk, index);
2134 break;
2135 case MGMT_OP_STOP_DISCOVERY:
2136 err = stop_discovery(sk, index);
2137 break;
2138 case MGMT_OP_RESOLVE_NAME:
2139 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2140 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002141 case MGMT_OP_READ_LOCAL_OOB_DATA:
2142 err = read_local_oob_data(sk, index);
2143 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002144 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2145 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2146 break;
2147 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2148 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2149 len);
2150 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151
Johan Hedberg03811012010-12-08 00:21:06 +02002152 default:
2153 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002154 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002155 break;
2156 }
2157
Johan Hedberge41d8b42010-12-13 21:07:03 +02002158 if (err < 0)
2159 goto done;
2160
Johan Hedberg03811012010-12-08 00:21:06 +02002161 err = msglen;
2162
2163done:
2164 kfree(buf);
2165 return err;
2166}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002167
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002168int mgmt_index_added(u16 index)
2169{
Brian Gixa68668b2011-08-11 15:49:36 -07002170 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002171 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002172}
2173
2174int mgmt_index_removed(u16 index)
2175{
Brian Gixa68668b2011-08-11 15:49:36 -07002176 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002177 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002178}
2179
Johan Hedberg73f22f62010-12-29 16:00:25 +02002180struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002181 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002182 struct sock *sk;
2183};
2184
Johan Hedberg72a734e2010-12-30 00:38:22 +02002185static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002186{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002187 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002188 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002189
Johan Hedberg72a734e2010-12-30 00:38:22 +02002190 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002191 return;
2192
Johan Hedberg053f0212011-01-26 13:07:10 +02002193 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002194
2195 list_del(&cmd->list);
2196
2197 if (match->sk == NULL) {
2198 match->sk = cmd->sk;
2199 sock_hold(match->sk);
2200 }
2201
2202 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002203}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002204
2205int mgmt_powered(u16 index, u8 powered)
2206{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002207 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002208 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002209 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002210
Brian Gixa68668b2011-08-11 15:49:36 -07002211 BT_DBG("hci%u %d", index, powered);
2212
Johan Hedberg72a734e2010-12-30 00:38:22 +02002213 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002214
Johan Hedberg72a734e2010-12-30 00:38:22 +02002215 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002216
Szymon Janc4e51eae2011-02-25 19:05:48 +01002217 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002218
2219 if (match.sk)
2220 sock_put(match.sk);
2221
2222 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002223}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002224
Johan Hedberg73f22f62010-12-29 16:00:25 +02002225int mgmt_discoverable(u16 index, u8 discoverable)
2226{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002227 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002228 struct cmd_lookup match = { discoverable, NULL };
2229 int ret;
2230
Szymon Jancb8534e02011-03-01 16:55:34 +01002231 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002232
Johan Hedberg72a734e2010-12-30 00:38:22 +02002233 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002234
Szymon Janc4e51eae2011-02-25 19:05:48 +01002235 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2236 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002237
2238 if (match.sk)
2239 sock_put(match.sk);
2240
2241 return ret;
2242}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002243
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002244int mgmt_connectable(u16 index, u8 connectable)
2245{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002246 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002247 struct cmd_lookup match = { connectable, NULL };
2248 int ret;
2249
Johan Hedberg72a734e2010-12-30 00:38:22 +02002250 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002251
Johan Hedberg72a734e2010-12-30 00:38:22 +02002252 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002253
Szymon Janc4e51eae2011-02-25 19:05:48 +01002254 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002255
2256 if (match.sk)
2257 sock_put(match.sk);
2258
2259 return ret;
2260}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002261
Brian Gixa68668b2011-08-11 15:49:36 -07002262int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002263{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002264 struct mgmt_ev_new_key *ev;
2265 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002266
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002267 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2268 ev = kzalloc(total, GFP_ATOMIC);
2269 if (!ev)
2270 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002271
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002272 bacpy(&ev->key.bdaddr, &key->bdaddr);
2273 ev->key.type = key->type;
2274 memcpy(ev->key.val, key->val, 16);
2275 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002276 ev->key.auth = key->auth;
2277 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002278 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002279
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002280 memcpy(ev->key.data, key->data, key->dlen);
2281
2282 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2283
2284 kfree(ev);
2285
2286 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002287}
Johan Hedbergf7520542011-01-20 12:34:39 +02002288
Brian Gix2e2f50d2011-09-13 12:36:04 -07002289int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002290{
2291 struct mgmt_ev_connected ev;
2292
Johan Hedbergf7520542011-01-20 12:34:39 +02002293 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002294 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002295
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}