blob: b413a9cd8cb16eb6a887e72ffe041aa4505abd66 [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 {
Brian Gixa68668b2011-08-11 15:49:36 -070044 u16 index;
45 enum scan_mode mode;
46 int int_phase;
47 int int_count;
48};
49
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020050struct pending_cmd {
51 struct list_head list;
52 __u16 opcode;
53 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010054 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020055 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030056 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057};
58
Mat Martineau8cd0df02011-08-23 16:23:36 -070059struct mgmt_pending_free_work {
60 struct work_struct work;
61 struct sock *sk;
62};
63
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020065
Szymon Janc4e51eae2011-02-25 19:05:48 +010066static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020067{
68 struct sk_buff *skb;
69 struct mgmt_hdr *hdr;
70 struct mgmt_ev_cmd_status *ev;
71
Szymon Janc34eb5252011-02-28 14:10:08 +010072 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020073
74 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
75 if (!skb)
76 return -ENOMEM;
77
78 hdr = (void *) skb_put(skb, sizeof(*hdr));
79
80 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010081 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020082 hdr->len = cpu_to_le16(sizeof(*ev));
83
84 ev = (void *) skb_put(skb, sizeof(*ev));
85 ev->status = status;
86 put_unaligned_le16(cmd, &ev->opcode);
87
88 if (sock_queue_rcv_skb(sk, skb) < 0)
89 kfree_skb(skb);
90
91 return 0;
92}
93
Szymon Janc4e51eae2011-02-25 19:05:48 +010094static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
95 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020096{
97 struct sk_buff *skb;
98 struct mgmt_hdr *hdr;
99 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +0200100
101 BT_DBG("sock %p", sk);
102
Johan Hedberga38528f2011-01-22 06:46:43 +0200103 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200104 if (!skb)
105 return -ENOMEM;
106
107 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200108
Johan Hedberg02d98122010-12-13 21:07:04 +0200109 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100110 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200111 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200112
Johan Hedberga38528f2011-01-22 06:46:43 +0200113 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
114 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100115
116 if (rp)
117 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200118
119 if (sock_queue_rcv_skb(sk, skb) < 0)
120 kfree_skb(skb);
121
122 return 0;
123}
124
Johan Hedberga38528f2011-01-22 06:46:43 +0200125static int read_version(struct sock *sk)
126{
127 struct mgmt_rp_read_version rp;
128
129 BT_DBG("sock %p", sk);
130
131 rp.version = MGMT_VERSION;
132 put_unaligned_le16(MGMT_REVISION, &rp.revision);
133
Szymon Janc4e51eae2011-02-25 19:05:48 +0100134 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
135 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200136}
137
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200138static int read_index_list(struct sock *sk)
139{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 struct mgmt_rp_read_index_list *rp;
141 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200142 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200143 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200144 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200145
146 BT_DBG("sock %p", sk);
147
148 read_lock(&hci_dev_list_lock);
149
150 count = 0;
151 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700152 struct hci_dev *d = list_entry(p, struct hci_dev, list);
153 if (d->dev_type != HCI_BREDR)
154 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200155 count++;
156 }
157
Johan Hedberga38528f2011-01-22 06:46:43 +0200158 rp_len = sizeof(*rp) + (2 * count);
159 rp = kmalloc(rp_len, GFP_ATOMIC);
160 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100161 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200162 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100163 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200164
Brian Gixa68668b2011-08-11 15:49:36 -0700165 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166
167 i = 0;
168 list_for_each(p, &hci_dev_list) {
169 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200170
171 hci_del_off_timer(d);
172
Peter Krystad1fc44072011-08-30 15:38:12 -0700173 if (d->dev_type != HCI_BREDR)
174 continue;
175
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200176 set_bit(HCI_MGMT, &d->flags);
177
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200178 if (test_bit(HCI_SETUP, &d->flags))
179 continue;
180
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200181 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700182 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200183 BT_DBG("Added hci%u", d->id);
184 }
185
186 read_unlock(&hci_dev_list_lock);
187
Szymon Janc4e51eae2011-02-25 19:05:48 +0100188 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
189 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 kfree(rp);
192
193 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200197{
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200200
Szymon Janc4e51eae2011-02-25 19:05:48 +0100201 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200202
Szymon Janc4e51eae2011-02-25 19:05:48 +0100203 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200204 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100205 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200207 hci_del_off_timer(hdev);
208
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800209 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200211 set_bit(HCI_MGMT, &hdev->flags);
212
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200213 memset(&rp, 0, sizeof(rp));
214
Johan Hedberga38528f2011-01-22 06:46:43 +0200215 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200216
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.powered = test_bit(HCI_UP, &hdev->flags);
218 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
219 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
220 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221
222 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200223 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200224 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200225 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200227 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228
Johan Hedberga38528f2011-01-22 06:46:43 +0200229 bacpy(&rp.bdaddr, &hdev->bdaddr);
230 memcpy(rp.features, hdev->features, 8);
231 memcpy(rp.dev_class, hdev->dev_class, 3);
232 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
233 rp.hci_ver = hdev->hci_ver;
234 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200236 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
237
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800238 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200239 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200240
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200242}
243
Mat Martineau8cd0df02011-08-23 16:23:36 -0700244static void mgmt_pending_free_worker(struct work_struct *work)
245{
246 struct mgmt_pending_free_work *free_work =
247 container_of(work, struct mgmt_pending_free_work, work);
248
249 BT_DBG("sk %p", free_work->sk);
250
251 sock_put(free_work->sk);
252 kfree(free_work);
253}
254
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200255static void mgmt_pending_free(struct pending_cmd *cmd)
256{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700257 struct mgmt_pending_free_work *free_work;
258 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700259
Mat Martineau8cd0df02011-08-23 16:23:36 -0700260 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
261
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100262 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200263 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700264
265 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
266 if (free_work) {
267 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
268 free_work->sk = sk;
269
270 if (!schedule_work(&free_work->work))
271 kfree(free_work);
272 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200273}
274
Johan Hedberg366a0332011-02-19 12:05:55 -0300275static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
276 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200277{
278 struct pending_cmd *cmd;
279
Brian Gixa68668b2011-08-11 15:49:36 -0700280 BT_DBG("%d", opcode);
281
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
283 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300284 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200285
286 cmd->opcode = opcode;
287 cmd->index = index;
288
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100289 cmd->param = kmalloc(len, GFP_ATOMIC);
290 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200291 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300292 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200293 }
294
Szymon Janc8fce6352011-03-22 13:12:20 +0100295 if (data)
296 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200297
298 cmd->sk = sk;
299 sock_hold(sk);
300
301 list_add(&cmd->list, &cmd_list);
302
Johan Hedberg366a0332011-02-19 12:05:55 -0300303 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304}
305
306static void mgmt_pending_foreach(u16 opcode, int index,
307 void (*cb)(struct pending_cmd *cmd, void *data),
308 void *data)
309{
310 struct list_head *p, *n;
311
Brian Gixa68668b2011-08-11 15:49:36 -0700312 BT_DBG(" %d", opcode);
313
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200314 list_for_each_safe(p, n, &cmd_list) {
315 struct pending_cmd *cmd;
316
317 cmd = list_entry(p, struct pending_cmd, list);
318
319 if (cmd->opcode != opcode)
320 continue;
321
322 if (index >= 0 && cmd->index != index)
323 continue;
324
325 cb(cmd, data);
326 }
327}
328
329static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
330{
331 struct list_head *p;
332
Brian Gixa68668b2011-08-11 15:49:36 -0700333 BT_DBG(" %d", opcode);
334
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335 list_for_each(p, &cmd_list) {
336 struct pending_cmd *cmd;
337
338 cmd = list_entry(p, struct pending_cmd, list);
339
340 if (cmd->opcode != opcode)
341 continue;
342
343 if (index >= 0 && cmd->index != index)
344 continue;
345
346 return cmd;
347 }
348
349 return NULL;
350}
351
Johan Hedberga664b5b2011-02-19 12:06:02 -0300352static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353{
Brian Gixa68668b2011-08-11 15:49:36 -0700354 BT_DBG(" %d", cmd->opcode);
355
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 list_del(&cmd->list);
357 mgmt_pending_free(cmd);
358}
359
Szymon Janc4e51eae2011-02-25 19:05:48 +0100360static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200361{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200362 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300364 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300365 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200366
367 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200368
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200370
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100371 if (len != sizeof(*cp))
372 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
373
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100376 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800378 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200379
380 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200381 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100382 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200383 goto failed;
384 }
385
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
387 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200388 goto failed;
389 }
390
Szymon Janc4e51eae2011-02-25 19:05:48 +0100391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300392 if (!cmd) {
393 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200394 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396
Johan Hedberg72a734e2010-12-30 00:38:22 +0200397 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398 queue_work(hdev->workqueue, &hdev->power_on);
399 else
400 queue_work(hdev->workqueue, &hdev->power_off);
401
Johan Hedberg366a0332011-02-19 12:05:55 -0300402 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200403
404failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800405 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200406 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300407 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200408}
409
Brian Gix8a7f1642011-10-17 17:39:46 -0700410static u8 get_service_classes(struct hci_dev *hdev)
411{
412 struct list_head *p;
413 u8 val = 0;
414
415 list_for_each(p, &hdev->uuids) {
416 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
417
418 val |= uuid->svc_hint;
419 }
420
421 return val;
422}
423
424static int update_class(struct hci_dev *hdev)
425{
426 u8 cod[3];
427
428 BT_DBG("%s", hdev->name);
429
430 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
431 return 0;
432
433 cod[0] = hdev->minor_class;
434 cod[1] = hdev->major_class;
435 cod[2] = get_service_classes(hdev);
436
437 if (memcmp(cod, hdev->dev_class, 3) == 0)
438 return 0;
439
440 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
441}
442
443static int set_limited_discoverable(struct sock *sk, u16 index,
444 unsigned char *data, u16 len)
445{
446 struct mgmt_mode *cp;
447 struct hci_dev *hdev;
448 struct pending_cmd *cmd;
449 struct hci_cp_write_current_iac_lap dcp;
450 int update_cod;
451 int err = 0;
452 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
453 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
454
455 cp = (void *) data;
456
457 BT_DBG("hci%u discoverable: %d", index, cp->val);
458
459 if (!cp || len != sizeof(*cp))
460 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
461 EINVAL);
462
463 hdev = hci_dev_get(index);
464 if (!hdev)
465 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
466 ENODEV);
467
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800468 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700469
470 if (!test_bit(HCI_UP, &hdev->flags)) {
471 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
472 ENETDOWN);
473 goto failed;
474 }
475
476 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
477 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
478 EBUSY);
479 goto failed;
480 }
481
482 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
483 test_bit(HCI_PSCAN, &hdev->flags)) {
484 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
485 EALREADY);
486 goto failed;
487 }
488
489 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
490 len);
491 if (!cmd) {
492 err = -ENOMEM;
493 goto failed;
494 }
495
496 memset(&dcp, 0, sizeof(dcp));
497 dcp.num_current_iac = cp->val ? 2 : 1;
498 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
499 update_cod = 1;
500
501 if (cp->val) {
502 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
503 update_cod = 0;
504 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
505 } else {
506 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
507 update_cod = 0;
508 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
509 }
510
511 if (update_cod)
512 err = update_class(hdev);
513
514 if (err >= 0)
515 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
516 sizeof(dcp), &dcp);
517
518 if (err < 0)
519 mgmt_pending_remove(cmd);
520
521failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800522 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700523 hci_dev_put(hdev);
524
525 return err;
526}
527
Szymon Janc4e51eae2011-02-25 19:05:48 +0100528static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
529 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200530{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200531 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200532 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300533 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200534 u8 scan;
535 int err;
536
537 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200538
Szymon Janc4e51eae2011-02-25 19:05:48 +0100539 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200540
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100541 if (len != sizeof(*cp))
542 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
543
Szymon Janc4e51eae2011-02-25 19:05:48 +0100544 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200545 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100546 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200547
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800548 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200549
550 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100551 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200552 goto failed;
553 }
554
Szymon Janc4e51eae2011-02-25 19:05:48 +0100555 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
556 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
557 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200558 goto failed;
559 }
560
Johan Hedberg72a734e2010-12-30 00:38:22 +0200561 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200562 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100563 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200564 goto failed;
565 }
566
Szymon Janc4e51eae2011-02-25 19:05:48 +0100567 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300568 if (!cmd) {
569 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200570 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300571 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200572
573 scan = SCAN_PAGE;
574
Johan Hedberg72a734e2010-12-30 00:38:22 +0200575 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200576 scan |= SCAN_INQUIRY;
577
578 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
579 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300580 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200581
582failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800583 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200584 hci_dev_put(hdev);
585
586 return err;
587}
588
Szymon Janc4e51eae2011-02-25 19:05:48 +0100589static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
590 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200591{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200592 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200593 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300594 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200595 u8 scan;
596 int err;
597
598 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200599
Szymon Janc4e51eae2011-02-25 19:05:48 +0100600 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200601
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100602 if (len != sizeof(*cp))
603 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
604
Szymon Janc4e51eae2011-02-25 19:05:48 +0100605 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200606 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100607 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200608
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800609 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200610
611 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100612 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200613 goto failed;
614 }
615
Szymon Janc4e51eae2011-02-25 19:05:48 +0100616 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
617 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
618 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200619 goto failed;
620 }
621
Johan Hedberg72a734e2010-12-30 00:38:22 +0200622 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100623 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200624 goto failed;
625 }
626
Szymon Janc4e51eae2011-02-25 19:05:48 +0100627 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300628 if (!cmd) {
629 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200630 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300631 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200632
Johan Hedberg72a734e2010-12-30 00:38:22 +0200633 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200634 scan = SCAN_PAGE;
635 else
636 scan = 0;
637
638 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
639 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300640 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200641
642failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800643 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200644 hci_dev_put(hdev);
645
646 return err;
647}
648
Szymon Janc4e51eae2011-02-25 19:05:48 +0100649static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
650 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200651{
652 struct sk_buff *skb;
653 struct mgmt_hdr *hdr;
654
Brian Gixa68668b2011-08-11 15:49:36 -0700655 BT_DBG("hci%d %d", index, event);
656
Johan Hedbergc542a062011-01-26 13:11:03 +0200657 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
658 if (!skb)
659 return -ENOMEM;
660
661 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
662
663 hdr = (void *) skb_put(skb, sizeof(*hdr));
664 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100665 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200666 hdr->len = cpu_to_le16(data_len);
667
Szymon Janc4e51eae2011-02-25 19:05:48 +0100668 if (data)
669 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200670
671 hci_send_to_sock(NULL, skb, skip_sk);
672 kfree_skb(skb);
673
674 return 0;
675}
676
Johan Hedberg053f0212011-01-26 13:07:10 +0200677static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
678{
Johan Hedberga38528f2011-01-22 06:46:43 +0200679 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200680
Johan Hedberga38528f2011-01-22 06:46:43 +0200681 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200682
Szymon Janc4e51eae2011-02-25 19:05:48 +0100683 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200684}
685
Szymon Janc4e51eae2011-02-25 19:05:48 +0100686static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
687 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200688{
689 struct mgmt_mode *cp, ev;
690 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200691 int err;
692
693 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200694
Szymon Janc4e51eae2011-02-25 19:05:48 +0100695 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200696
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100697 if (len != sizeof(*cp))
698 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
699
Szymon Janc4e51eae2011-02-25 19:05:48 +0100700 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200701 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100702 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200703
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800704 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200705
706 if (cp->val)
707 set_bit(HCI_PAIRABLE, &hdev->flags);
708 else
709 clear_bit(HCI_PAIRABLE, &hdev->flags);
710
Szymon Janc4e51eae2011-02-25 19:05:48 +0100711 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200712 if (err < 0)
713 goto failed;
714
Johan Hedbergc542a062011-01-26 13:11:03 +0200715 ev.val = cp->val;
716
Szymon Janc4e51eae2011-02-25 19:05:48 +0100717 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200718
719failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800720 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200721 hci_dev_put(hdev);
722
723 return err;
724}
725
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300726#define EIR_FLAGS 0x01 /* flags */
727#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
728#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
729#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
730#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
731#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
732#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
733#define EIR_NAME_SHORT 0x08 /* shortened local name */
734#define EIR_NAME_COMPLETE 0x09 /* complete local name */
735#define EIR_TX_POWER 0x0A /* transmit power level */
736#define EIR_DEVICE_ID 0x10 /* device ID */
737
738#define PNP_INFO_SVCLASS_ID 0x1200
739
740static u8 bluetooth_base_uuid[] = {
741 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
742 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743};
744
745static u16 get_uuid16(u8 *uuid128)
746{
747 u32 val;
748 int i;
749
750 for (i = 0; i < 12; i++) {
751 if (bluetooth_base_uuid[i] != uuid128[i])
752 return 0;
753 }
754
755 memcpy(&val, &uuid128[12], 4);
756
757 val = le32_to_cpu(val);
758 if (val > 0xffff)
759 return 0;
760
761 return (u16) val;
762}
763
764static void create_eir(struct hci_dev *hdev, u8 *data)
765{
766 u8 *ptr = data;
767 u16 eir_len = 0;
768 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
769 int i, truncated = 0;
770 struct list_head *p;
771 size_t name_len;
772
773 name_len = strlen(hdev->dev_name);
774
775 if (name_len > 0) {
776 /* EIR Data type */
777 if (name_len > 48) {
778 name_len = 48;
779 ptr[1] = EIR_NAME_SHORT;
780 } else
781 ptr[1] = EIR_NAME_COMPLETE;
782
783 /* EIR Data length */
784 ptr[0] = name_len + 1;
785
786 memcpy(ptr + 2, hdev->dev_name, name_len);
787
788 eir_len += (name_len + 2);
789 ptr += (name_len + 2);
790 }
791
792 memset(uuid16_list, 0, sizeof(uuid16_list));
793
794 /* Group all UUID16 types */
795 list_for_each(p, &hdev->uuids) {
796 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
797 u16 uuid16;
798
799 uuid16 = get_uuid16(uuid->uuid);
800 if (uuid16 == 0)
801 return;
802
803 if (uuid16 < 0x1100)
804 continue;
805
806 if (uuid16 == PNP_INFO_SVCLASS_ID)
807 continue;
808
809 /* Stop if not enough space to put next UUID */
810 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
811 truncated = 1;
812 break;
813 }
814
815 /* Check for duplicates */
816 for (i = 0; uuid16_list[i] != 0; i++)
817 if (uuid16_list[i] == uuid16)
818 break;
819
820 if (uuid16_list[i] == 0) {
821 uuid16_list[i] = uuid16;
822 eir_len += sizeof(u16);
823 }
824 }
825
826 if (uuid16_list[0] != 0) {
827 u8 *length = ptr;
828
829 /* EIR Data type */
830 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
831
832 ptr += 2;
833 eir_len += 2;
834
835 for (i = 0; uuid16_list[i] != 0; i++) {
836 *ptr++ = (uuid16_list[i] & 0x00ff);
837 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
838 }
839
840 /* EIR Data length */
841 *length = (i * sizeof(u16)) + 1;
842 }
843}
844
845static int update_eir(struct hci_dev *hdev)
846{
847 struct hci_cp_write_eir cp;
848
849 if (!(hdev->features[6] & LMP_EXT_INQ))
850 return 0;
851
852 if (hdev->ssp_mode == 0)
853 return 0;
854
855 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
856 return 0;
857
858 memset(&cp, 0, sizeof(cp));
859
860 create_eir(hdev, cp.data);
861
862 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
863 return 0;
864
865 memcpy(hdev->eir, cp.data, sizeof(cp.data));
866
867 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
868}
869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200871{
872 struct mgmt_cp_add_uuid *cp;
873 struct hci_dev *hdev;
874 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200875 int err;
876
877 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200880
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100881 if (len != sizeof(*cp))
882 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200885 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800888 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889
890 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
891 if (!uuid) {
892 err = -ENOMEM;
893 goto failed;
894 }
895
896 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200898
899 list_add(&uuid->list, &hdev->uuids);
900
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200901 err = update_class(hdev);
902 if (err < 0)
903 goto failed;
904
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300905 err = update_eir(hdev);
906 if (err < 0)
907 goto failed;
908
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200910
911failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800912 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200913 hci_dev_put(hdev);
914
915 return err;
916}
917
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200919{
920 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100921 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200922 struct hci_dev *hdev;
923 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 +0200924 int err, found;
925
926 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100930 if (len != sizeof(*cp))
931 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100935 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200936
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800937 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200938
939 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
940 err = hci_uuids_clear(hdev);
941 goto unlock;
942 }
943
944 found = 0;
945
946 list_for_each_safe(p, n, &hdev->uuids) {
947 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
948
949 if (memcmp(match->uuid, cp->uuid, 16) != 0)
950 continue;
951
952 list_del(&match->list);
953 found++;
954 }
955
956 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100957 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200958 goto unlock;
959 }
960
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200961 err = update_class(hdev);
962 if (err < 0)
963 goto unlock;
964
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300965 err = update_eir(hdev);
966 if (err < 0)
967 goto unlock;
968
Szymon Janc4e51eae2011-02-25 19:05:48 +0100969 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200970
971unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800972 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200973 hci_dev_put(hdev);
974
975 return err;
976}
977
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
979 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200980{
981 struct hci_dev *hdev;
982 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200983 int err;
984
985 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200986
Szymon Janc4e51eae2011-02-25 19:05:48 +0100987 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100989 if (len != sizeof(*cp))
990 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
991
Szymon Janc4e51eae2011-02-25 19:05:48 +0100992 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200993 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100994 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200995
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800996 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200997
Brian Gix8a7f1642011-10-17 17:39:46 -0700998 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
999 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000 hdev->minor_class = cp->minor;
1001
1002 err = update_class(hdev);
1003
1004 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001005 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001007 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008 hci_dev_put(hdev);
1009
1010 return err;
1011}
1012
Szymon Janc4e51eae2011-02-25 19:05:48 +01001013static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1014 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001015{
1016 struct hci_dev *hdev;
1017 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018 int err;
1019
1020 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001021
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001022 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001023 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001024
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001026 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001028
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001029 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001030
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001032
1033 if (cp->enable) {
1034 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1035 err = 0;
1036 } else {
1037 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
1038 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001039 if (err == 0)
1040 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001041 }
1042
1043 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001044 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1045 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001046
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001047 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001048 hci_dev_put(hdev);
1049
1050 return err;
1051}
1052
Szymon Janc4e51eae2011-02-25 19:05:48 +01001053static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001054{
1055 struct hci_dev *hdev;
1056 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001057 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001058 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001059
1060 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001061
1062 if (len < sizeof(*cp))
1063 return -EINVAL;
1064
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001065 key_count = get_unaligned_le16(&cp->key_count);
1066
1067 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001068 if (expected_len > len) {
1069 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1070 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001071 return -EINVAL;
1072 }
1073
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001075 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001077
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001079 key_count);
1080
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001081 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001082
1083 hci_link_keys_clear(hdev);
1084
1085 set_bit(HCI_LINK_KEYS, &hdev->flags);
1086
1087 if (cp->debug_keys)
1088 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1089 else
1090 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1091
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001092 len -= sizeof(*cp);
1093 i = 0;
1094
1095 while (i < len) {
1096 struct mgmt_key_info *key = (void *) cp->keys + i;
1097
Brian Gixa68668b2011-08-11 15:49:36 -07001098 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001099
Brian Gixcf956772011-10-20 15:18:51 -07001100 if (key->key_type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001101 struct key_master_id *id = (void *) key->data;
1102
1103 if (key->dlen != sizeof(struct key_master_id))
1104 continue;
1105
Brian Gixcf956772011-10-20 15:18:51 -07001106 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1107 key->pin_len, key->auth, id->ediv,
1108 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001109
1110 continue;
1111 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001112
Brian Gixcf956772011-10-20 15:18:51 -07001113 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001114 key->pin_len);
1115 }
1116
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001117 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1118
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001119 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001120 hci_dev_put(hdev);
1121
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001122 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001123}
1124
Szymon Janc4e51eae2011-02-25 19:05:48 +01001125static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001126{
1127 struct hci_dev *hdev;
1128 struct mgmt_cp_remove_key *cp;
1129 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001130 int err;
1131
1132 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001133
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001134 if (len != sizeof(*cp))
1135 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1136
Szymon Janc4e51eae2011-02-25 19:05:48 +01001137 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001138 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001139 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001140
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001141 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001142
1143 err = hci_remove_link_key(hdev, &cp->bdaddr);
1144 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001145 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001146 goto unlock;
1147 }
1148
1149 err = 0;
1150
1151 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1152 goto unlock;
1153
1154 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1155 if (conn) {
1156 struct hci_cp_disconnect dc;
1157
1158 put_unaligned_le16(conn->handle, &dc.handle);
1159 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001161 }
1162
1163unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001164 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001165 hci_dev_put(hdev);
1166
1167 return err;
1168}
1169
Szymon Janc4e51eae2011-02-25 19:05:48 +01001170static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001171{
1172 struct hci_dev *hdev;
1173 struct mgmt_cp_disconnect *cp;
1174 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001175 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001176 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177 int err;
1178
1179 BT_DBG("");
1180
1181 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001182
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001183 if (len != sizeof(*cp))
1184 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1185
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001187 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001188 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001190 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191
1192 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001193 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194 goto failed;
1195 }
1196
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1198 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001199 goto failed;
1200 }
1201
1202 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1203 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001204 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1205 if (!conn) {
1206 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1207 ENOTCONN);
1208 goto failed;
1209 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001210 }
1211
Szymon Janc4e51eae2011-02-25 19:05:48 +01001212 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001213 if (!cmd) {
1214 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001215 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001216 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001217
1218 put_unaligned_le16(conn->handle, &dc.handle);
1219 dc.reason = 0x13; /* Remote User Terminated Connection */
1220
1221 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1222 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001223 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001224
1225failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001226 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001227 hci_dev_put(hdev);
1228
1229 return err;
1230}
1231
Szymon Janc8ce62842011-03-01 16:55:32 +01001232static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001233{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001234 struct mgmt_rp_get_connections *rp;
1235 struct hci_dev *hdev;
1236 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001237 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001239 int i, err;
1240
1241 BT_DBG("");
1242
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001247 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248
1249 count = 0;
1250 list_for_each(p, &hdev->conn_hash.list) {
1251 count++;
1252 }
1253
Johan Hedberga38528f2011-01-22 06:46:43 +02001254 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1255 rp = kmalloc(rp_len, GFP_ATOMIC);
1256 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001257 err = -ENOMEM;
1258 goto unlock;
1259 }
1260
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261 put_unaligned_le16(count, &rp->conn_count);
1262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 read_lock(&hci_dev_list_lock);
1264
Johan Hedberg2784eb42011-01-21 13:56:35 +02001265 i = 0;
1266 list_for_each(p, &hdev->conn_hash.list) {
1267 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1268
1269 bacpy(&rp->conn[i++], &c->dst);
1270 }
1271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 read_unlock(&hci_dev_list_lock);
1273
Szymon Janc4e51eae2011-02-25 19:05:48 +01001274 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001275
1276unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001277 kfree(rp);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001278 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001279 hci_dev_put(hdev);
1280 return err;
1281}
1282
Szymon Janc4e51eae2011-02-25 19:05:48 +01001283static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1284 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001285{
1286 struct hci_dev *hdev;
1287 struct mgmt_cp_pin_code_reply *cp;
1288 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001289 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001290 int err;
1291
1292 BT_DBG("");
1293
1294 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001295
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001296 if (len != sizeof(*cp))
1297 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1298
Szymon Janc4e51eae2011-02-25 19:05:48 +01001299 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001300 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001303 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001304
1305 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001307 goto failed;
1308 }
1309
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001311 if (!cmd) {
1312 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001313 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001314 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315
1316 bacpy(&reply.bdaddr, &cp->bdaddr);
1317 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319
1320 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1321 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001322 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001323
1324failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001325 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001326 hci_dev_put(hdev);
1327
1328 return err;
1329}
1330
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301331static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1332 u16 len)
1333{
1334 struct hci_dev *hdev;
1335 struct mgmt_cp_encrypt_link *cp;
1336 struct hci_cp_set_conn_encrypt enc;
1337 struct hci_conn *conn;
1338 int err = 0;
1339
1340 BT_DBG("");
1341
1342 cp = (void *) data;
1343
1344 if (len != sizeof(*cp))
1345 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1346
1347 hdev = hci_dev_get(index);
1348 if (!hdev)
1349 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1350
1351 hci_dev_lock(hdev);
1352
1353 if (!test_bit(HCI_UP, &hdev->flags)) {
1354 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
1355 goto failed;
1356 }
1357
1358 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1359 &cp->bdaddr);
1360 if (!conn)
1361 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1362
1363 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
1364 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1365
1366 if (conn->link_mode & HCI_LM_AUTH) {
1367 enc.handle = cpu_to_le16(conn->handle);
1368 enc.encrypt = cp->enable;
1369 err = hci_send_cmd(hdev,
1370 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1371 } else {
1372 conn->auth_initiator = 1;
1373 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1374 struct hci_cp_auth_requested cp;
1375 cp.handle = cpu_to_le16(conn->handle);
1376 err = hci_send_cmd(conn->hdev,
1377 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1378 }
1379 }
1380
1381failed:
1382 hci_dev_unlock(hdev);
1383 hci_dev_put(hdev);
1384
1385 return err;
1386}
1387
1388
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1390 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001391{
1392 struct hci_dev *hdev;
1393 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395 int err;
1396
1397 BT_DBG("");
1398
1399 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001401 if (len != sizeof(*cp))
1402 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1403 EINVAL);
1404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001406 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1408 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001409
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001410 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411
1412 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1414 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001415 goto failed;
1416 }
1417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1419 data, len);
1420 if (!cmd) {
1421 err = -ENOMEM;
1422 goto failed;
1423 }
1424
1425 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1426 &cp->bdaddr);
1427 if (err < 0)
1428 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001429
1430failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001431 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001432 hci_dev_put(hdev);
1433
1434 return err;
1435}
1436
Szymon Janc4e51eae2011-02-25 19:05:48 +01001437static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1438 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001439{
1440 struct hci_dev *hdev;
1441 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001442
1443 BT_DBG("");
1444
1445 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001446
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001447 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001448 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001451 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001453
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001454 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455
1456 hdev->io_capability = cp->io_capability;
1457
1458 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001459 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001460
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001461 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462 hci_dev_put(hdev);
1463
Szymon Janc4e51eae2011-02-25 19:05:48 +01001464 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001465}
1466
Johan Hedberge9a416b2011-02-19 12:05:56 -03001467static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1468{
1469 struct hci_dev *hdev = conn->hdev;
1470 struct list_head *p;
1471
1472 list_for_each(p, &cmd_list) {
1473 struct pending_cmd *cmd;
1474
1475 cmd = list_entry(p, struct pending_cmd, list);
1476
1477 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1478 continue;
1479
1480 if (cmd->index != hdev->id)
1481 continue;
1482
1483 if (cmd->user_data != conn)
1484 continue;
1485
1486 return cmd;
1487 }
1488
1489 return NULL;
1490}
1491
1492static void pairing_complete(struct pending_cmd *cmd, u8 status)
1493{
1494 struct mgmt_rp_pair_device rp;
1495 struct hci_conn *conn = cmd->user_data;
1496
Brian Gixa68668b2011-08-11 15:49:36 -07001497 BT_DBG(" %u", status);
1498
Johan Hedberge9a416b2011-02-19 12:05:56 -03001499 bacpy(&rp.bdaddr, &conn->dst);
1500 rp.status = status;
1501
Szymon Janc4e51eae2011-02-25 19:05:48 +01001502 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001503
1504 /* So we don't get further callbacks for this connection */
1505 conn->connect_cfm_cb = NULL;
1506 conn->security_cfm_cb = NULL;
1507 conn->disconn_cfm_cb = NULL;
1508
Johan Hedberga664b5b2011-02-19 12:06:02 -03001509 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001510}
1511
1512static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1513{
1514 struct pending_cmd *cmd;
1515
Brian Gixa68668b2011-08-11 15:49:36 -07001516 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001517
1518 cmd = find_pairing(conn);
1519 if (!cmd) {
1520 BT_DBG("Unable to find a pending command");
1521 return;
1522 }
1523
1524 pairing_complete(cmd, status);
1525}
1526
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001527static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001528{
1529 struct pending_cmd *cmd;
1530
1531 BT_DBG(" %u", status);
1532
1533 cmd = find_pairing(conn);
1534 if (!cmd) {
1535 BT_DBG("Unable to find a pending command");
1536 return;
1537 }
1538
1539 if (conn->type == LE_LINK)
1540 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1541 status ? 0 : 1);
1542 else
1543 pairing_complete(cmd, status);
1544}
1545
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001546static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001547{
1548 struct pending_cmd *cmd;
1549
1550 BT_DBG("conn: %p %u", conn, status);
1551
1552 cmd = find_pairing(conn);
1553 if (!cmd) {
1554 BT_DBG("Unable to find a pending command");
1555 return;
1556 }
Brian Gix114f3a62011-09-27 14:02:20 -07001557
1558 if (status)
1559 pairing_complete(cmd, status);
1560
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001561 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001562}
1563
1564static void discovery_terminated(struct pending_cmd *cmd, void *data)
1565{
Brian Gix6e349d02011-11-28 14:51:14 -08001566 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001567 struct mgmt_mode ev = {0};
Brian Gixa68668b2011-08-11 15:49:36 -07001568
1569 BT_DBG("");
Brian Gix6e349d02011-11-28 14:51:14 -08001570 hdev = hci_dev_get(cmd->index);
1571 if (!hdev)
1572 goto not_found;
1573
1574 del_timer_sync(&hdev->disc_le_timer);
1575 del_timer_sync(&hdev->disc_timer);
1576 hci_dev_put(hdev);
1577
1578not_found:
Brian Gixa68668b2011-08-11 15:49:36 -07001579 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1580
1581 list_del(&cmd->list);
1582
1583 mgmt_pending_free(cmd);
1584}
1585
Szymon Janc4e51eae2011-02-25 19:05:48 +01001586static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001587{
1588 struct hci_dev *hdev;
1589 struct mgmt_cp_pair_device *cp;
1590 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001591 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001592 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001593 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001594 int err;
1595
1596 BT_DBG("");
1597
Brian Gix64bd5302011-09-08 11:35:48 -07001598 cp = (void *) data;
1599
1600 if (len != sizeof(*cp))
1601 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1602
Szymon Janc4e51eae2011-02-25 19:05:48 +01001603 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001604
Johan Hedberge9a416b2011-02-19 12:05:56 -03001605 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001607
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001608 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001609
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301610 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1611 io_cap = cp->io_cap;
1612 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001613 sec_level = BT_SECURITY_MEDIUM;
1614 auth_type = HCI_AT_DEDICATED_BONDING;
1615 } else {
1616 sec_level = BT_SECURITY_HIGH;
1617 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1618 }
1619
Brian Gixfdd38922011-09-28 16:23:48 -07001620 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1621 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001622 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1623 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001624 } else {
1625 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1626 if (io_cap == 0x04)
1627 io_cap = 0x01;
1628 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1629 auth_type);
1630 }
1631
Ville Tervo30e76272011-02-22 16:10:53 -03001632 if (IS_ERR(conn)) {
1633 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001634 goto unlock;
1635 }
1636
1637 if (conn->connect_cfm_cb) {
1638 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001639 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001640 goto unlock;
1641 }
1642
Szymon Janc4e51eae2011-02-25 19:05:48 +01001643 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001644 if (!cmd) {
1645 err = -ENOMEM;
1646 hci_conn_put(conn);
1647 goto unlock;
1648 }
1649
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001650 conn->connect_cfm_cb = pairing_connect_complete_cb;
1651 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001652 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001653 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001654 cmd->user_data = conn;
1655
1656 if (conn->state == BT_CONNECTED &&
1657 hci_conn_security(conn, sec_level, auth_type))
1658 pairing_complete(cmd, 0);
1659
1660 err = 0;
1661
1662unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001663 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001664 hci_dev_put(hdev);
1665
1666 return err;
1667}
1668
Szymon Janc4e51eae2011-02-25 19:05:48 +01001669static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001670 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001671{
1672 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001673 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001674 struct pending_cmd *cmd;
1675 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001676 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001677 int err;
1678
Brian Gixa68668b2011-08-11 15:49:36 -07001679 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001680
Brian Gixa68668b2011-08-11 15:49:36 -07001681 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001682 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001683 else
1684 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001685
Brian Gixa68668b2011-08-11 15:49:36 -07001686 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001687 return cmd_status(sk, index, mgmt_op, EINVAL);
1688
Szymon Janc4e51eae2011-02-25 19:05:48 +01001689 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001690 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001691 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001692
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001693 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001694
Johan Hedberga5c29682011-02-19 12:05:57 -03001695 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001696 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001697 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001698 }
1699
Brian Gixa68668b2011-08-11 15:49:36 -07001700 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1701 if (le_conn) {
1702 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1703 goto done;
1704 }
1705 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1706 "Reject" : "Accept");
1707
Szymon Janc4e51eae2011-02-25 19:05:48 +01001708 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001709 if (!cmd) {
1710 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001711 goto done;
1712 }
1713
1714 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1715 if (err < 0)
1716 mgmt_pending_remove(cmd);
1717
1718done:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001719 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001720 hci_dev_put(hdev);
1721
1722 return err;
1723}
1724
1725static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1726 u16 len)
1727{
1728 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1729 struct hci_cp_remote_name_req hci_cp;
1730 struct hci_dev *hdev;
1731 struct pending_cmd *cmd;
1732 int err;
1733
1734 BT_DBG("");
1735
1736 if (len != sizeof(*mgmt_cp))
1737 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1738
1739 hdev = hci_dev_get(index);
1740 if (!hdev)
1741 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1742
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001743 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001744
1745 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1746 if (!cmd) {
1747 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001748 goto failed;
1749 }
1750
Brian Gixa68668b2011-08-11 15:49:36 -07001751 memset(&hci_cp, 0, sizeof(hci_cp));
1752 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1753 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1754 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001755 if (err < 0)
1756 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001757
1758failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001759 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001760 hci_dev_put(hdev);
1761
1762 return err;
1763}
1764
Brian Gix7f7e16c2011-11-01 16:27:25 -07001765static int set_connection_params(struct sock *sk, u16 index,
1766 unsigned char *data, u16 len)
1767{
1768 struct mgmt_cp_set_connection_params *cp = (void *) data;
1769 struct hci_dev *hdev;
1770 struct hci_conn *conn;
1771 int err;
1772
1773 BT_DBG("");
1774
1775 if (len != sizeof(*cp))
1776 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1777 EINVAL);
1778
1779 hdev = hci_dev_get(index);
1780 if (!hdev)
1781 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1782 ENODEV);
1783
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001784 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001785
1786 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1787 if (!conn) {
1788 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1789 ENOTCONN);
1790 goto failed;
1791 }
1792
1793 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1794 le16_to_cpu(cp->interval_max),
1795 le16_to_cpu(cp->slave_latency),
1796 le16_to_cpu(cp->timeout_multiplier));
1797
1798 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1799
1800failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001801 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001802 hci_dev_put(hdev);
1803
1804 return err;
1805}
1806
Johan Hedbergb312b1612011-03-16 14:29:37 +02001807static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1808 u16 len)
1809{
1810 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1811 struct hci_cp_write_local_name hci_cp;
1812 struct hci_dev *hdev;
1813 struct pending_cmd *cmd;
1814 int err;
1815
1816 BT_DBG("");
1817
1818 if (len != sizeof(*mgmt_cp))
1819 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1820
1821 hdev = hci_dev_get(index);
1822 if (!hdev)
1823 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1824
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001825 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001826
1827 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1828 if (!cmd) {
1829 err = -ENOMEM;
1830 goto failed;
1831 }
1832
1833 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1834 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1835 &hci_cp);
1836 if (err < 0)
1837 mgmt_pending_remove(cmd);
1838
1839failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001840 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001841 hci_dev_put(hdev);
1842
1843 return err;
1844}
1845
Brian Gixa68668b2011-08-11 15:49:36 -07001846static void discovery_rsp(struct pending_cmd *cmd, void *data)
1847{
1848 struct mgmt_mode ev;
1849
1850 BT_DBG("");
1851 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1852 ev.val = 1;
1853 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1854 } else {
1855 ev.val = 0;
1856 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1857 NULL, 0);
1858 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
Brian Gix6e349d02011-11-28 14:51:14 -08001859 struct hci_dev *hdev = hci_dev_get(cmd->index);
1860 if (hdev) {
1861 del_timer_sync(&hdev->disc_le_timer);
1862 del_timer_sync(&hdev->disc_timer);
1863 hci_dev_put(hdev);
1864 }
Brian Gixa68668b2011-08-11 15:49:36 -07001865 }
1866 }
1867
1868 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1869
1870 list_del(&cmd->list);
1871
1872 mgmt_pending_free(cmd);
1873}
1874
1875void mgmt_inquiry_started(u16 index)
1876{
1877 BT_DBG("");
1878 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1879 discovery_rsp, NULL);
1880}
1881
1882void mgmt_inquiry_complete_evt(u16 index, u8 status)
1883{
1884 struct hci_dev *hdev;
1885 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1886 struct pending_cmd *cmd;
1887 int err = -1;
1888
1889 BT_DBG("");
1890
1891 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001892
Brian Gixa68668b2011-08-11 15:49:36 -07001893 if (!hdev || !lmp_le_capable(hdev)) {
1894 struct mgmt_mode cp = {0};
1895
1896 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1897 discovery_terminated, NULL);
1898
1899 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001900
Brian Gix64bd5302011-09-08 11:35:48 -07001901 if (hdev)
1902 goto done;
1903 else
1904 return;
1905 }
Brian Gixa68668b2011-08-11 15:49:36 -07001906
1907 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1908 if (cmd && cmd->param) {
1909 struct disco_interleave *ilp = cmd->param;
1910
1911 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1912 sizeof(le_cp), &le_cp);
Brian Gix6e349d02011-11-28 14:51:14 -08001913 if (err >= 0 && hdev) {
1914 mod_timer(&hdev->disc_le_timer, jiffies +
Brian Gixa68668b2011-08-11 15:49:36 -07001915 msecs_to_jiffies(ilp->int_phase * 1000));
1916 ilp->mode = SCAN_LE;
1917 } else
1918 ilp->mode = SCAN_IDLE;
1919 }
1920
1921 if (err < 0)
1922 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1923 discovery_terminated, NULL);
1924
Brian Gix64bd5302011-09-08 11:35:48 -07001925done:
Brian Gixa68668b2011-08-11 15:49:36 -07001926 hci_dev_put(hdev);
1927}
1928
1929static void disco_to(unsigned long data)
1930{
1931 struct disco_interleave *ilp = (void *)data;
1932 struct hci_dev *hdev;
1933 struct pending_cmd *cmd;
1934
1935 BT_DBG("hci%d", ilp->index);
1936
Brian Gixa68668b2011-08-11 15:49:36 -07001937 hdev = hci_dev_get(ilp->index);
1938
1939 if (hdev) {
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001940 hci_dev_lock_bh(hdev);
Brian Gix6e349d02011-11-28 14:51:14 -08001941 del_timer_sync(&hdev->disc_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07001942
1943 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1944
1945 if (ilp->mode != SCAN_IDLE) {
1946 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1947
1948 if (ilp->mode == SCAN_LE)
1949 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1950 sizeof(le_cp), &le_cp);
1951 else
1952 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1953 0, NULL);
1954
1955 ilp->mode = SCAN_IDLE;
1956 }
1957
1958 if (cmd) {
1959 struct mgmt_mode cp = {0};
1960
1961 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1962 sizeof(cp), NULL);
1963 mgmt_pending_remove(cmd);
1964 }
1965
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001966 hci_dev_unlock_bh(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001967 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001968 }
1969}
1970
1971static void disco_le_to(unsigned long data)
1972{
1973 struct disco_interleave *ilp = (void *)data;
1974 struct hci_dev *hdev;
1975 struct pending_cmd *cmd;
1976 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1977
1978 BT_DBG("hci%d", ilp->index);
1979
1980 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001981
1982 if (hdev) {
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001983 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001984
1985 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1986
1987 if (ilp->mode == SCAN_LE)
1988 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1989 sizeof(le_cp), &le_cp);
1990
1991 /* re-start BR scan */
1992 if (cmd) {
1993 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1994 ilp->int_phase *= 2;
1995 ilp->int_count = 0;
1996 cp.num_rsp = (u8) ilp->int_phase;
1997 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1998 ilp->mode = SCAN_BR;
1999 } else
2000 ilp->mode = SCAN_IDLE;
2001
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002002 hci_dev_unlock_bh(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07002003 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002004 }
2005}
2006
2007static int start_discovery(struct sock *sk, u16 index)
2008{
2009 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2010 struct hci_dev *hdev;
2011 struct pending_cmd *cmd;
2012 int err;
2013
2014 BT_DBG("");
2015
2016 hdev = hci_dev_get(index);
2017 if (!hdev)
2018 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2019
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002020 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002021
2022 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2023 if (!cmd) {
2024 err = -ENOMEM;
2025 goto failed;
2026 }
2027
2028 /* If LE Capable, we will alternate between BR/EDR and LE */
2029 if (lmp_le_capable(hdev)) {
2030 struct hci_cp_le_set_scan_parameters le_cp;
2031
2032 /* Shorten BR scan params */
2033 cp.num_rsp = 1;
2034 cp.length /= 2;
2035
2036 /* Setup LE scan params */
2037 memset(&le_cp, 0, sizeof(le_cp));
2038 le_cp.type = 0x01; /* Active scanning */
2039 /* The recommended value for scan interval and window is
2040 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2041 le_cp.interval = cpu_to_le16(0x0012);
2042 le_cp.window = cpu_to_le16(0x0012);
2043 le_cp.own_bdaddr_type = 0; /* Public address */
2044 le_cp.filter = 0; /* Accept all adv packets */
2045
2046 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2047 sizeof(le_cp), &le_cp);
2048 }
2049
2050 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2051
2052 if (err < 0)
2053 mgmt_pending_remove(cmd);
2054 else if (lmp_le_capable(hdev)) {
2055 struct disco_interleave il, *ilp;
2056
2057 il.int_phase = 1;
2058 il.int_count = 0;
2059 il.index = index;
2060 il.mode = SCAN_BR;
2061 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
2062 sizeof(struct disco_interleave));
2063 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2064 if (cmd) {
2065 ilp = cmd->param;
Brian Gix6e349d02011-11-28 14:51:14 -08002066 setup_timer(&hdev->disc_le_timer, disco_le_to,
Brian Gixa68668b2011-08-11 15:49:36 -07002067 (unsigned long) ilp);
Brian Gix6e349d02011-11-28 14:51:14 -08002068 setup_timer(&hdev->disc_timer, disco_to,
2069 (unsigned long) ilp);
2070 mod_timer(&hdev->disc_timer,
Brian Gixa68668b2011-08-11 15:49:36 -07002071 jiffies + msecs_to_jiffies(20000));
2072 }
2073 }
2074
2075failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002076 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002077 hci_dev_put(hdev);
2078
2079 return err;
2080}
2081
2082static int stop_discovery(struct sock *sk, u16 index)
2083{
2084 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2085 struct mgmt_mode mode_cp = {0};
2086 struct disco_interleave *ilp = NULL;
2087 struct hci_dev *hdev;
2088 struct pending_cmd *cmd = NULL;
2089 int err = -EPERM;
2090
2091 BT_DBG("");
2092
2093 hdev = hci_dev_get(index);
2094 if (!hdev)
2095 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2096
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002097 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002098
2099 if (lmp_le_capable(hdev)) {
2100 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2101 if (!cmd) {
2102 err = -ENOMEM;
2103 goto failed;
2104 }
2105
2106 ilp = cmd->param;
2107 }
2108
2109 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2110 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2111 sizeof(le_cp), &le_cp);
2112
2113 if (err < 0) {
2114 if (!ilp || (ilp->mode == SCAN_BR))
2115 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2116 0, NULL);
2117 }
2118
2119 if (ilp) {
2120 ilp->mode = SCAN_IDLE;
Brian Gix6e349d02011-11-28 14:51:14 -08002121 del_timer_sync(&hdev->disc_le_timer);
2122 del_timer_sync(&hdev->disc_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002123 }
2124
2125 if (err < 0 && cmd)
2126 mgmt_pending_remove(cmd);
2127
2128 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2129
2130failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002131 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002132 hci_dev_put(hdev);
2133
2134 if (err < 0)
2135 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2136 else
2137 return err;
2138}
2139
Szymon Jancc35938b2011-03-22 13:12:21 +01002140static int read_local_oob_data(struct sock *sk, u16 index)
2141{
2142 struct hci_dev *hdev;
2143 struct pending_cmd *cmd;
2144 int err;
2145
2146 BT_DBG("hci%u", index);
2147
2148 hdev = hci_dev_get(index);
2149 if (!hdev)
2150 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2151 ENODEV);
2152
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002153 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002154
2155 if (!test_bit(HCI_UP, &hdev->flags)) {
2156 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2157 ENETDOWN);
2158 goto unlock;
2159 }
2160
2161 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2162 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2163 EOPNOTSUPP);
2164 goto unlock;
2165 }
2166
2167 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2168 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2169 goto unlock;
2170 }
2171
2172 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2173 if (!cmd) {
2174 err = -ENOMEM;
2175 goto unlock;
2176 }
2177
2178 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2179 if (err < 0)
2180 mgmt_pending_remove(cmd);
2181
2182unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002183 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 hci_dev_put(hdev);
2185
2186 return err;
2187}
2188
Szymon Janc2763eda2011-03-22 13:12:22 +01002189static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2190 u16 len)
2191{
2192 struct hci_dev *hdev;
2193 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2194 int err;
2195
2196 BT_DBG("hci%u ", index);
2197
2198 if (len != sizeof(*cp))
2199 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2200 EINVAL);
2201
2202 hdev = hci_dev_get(index);
2203 if (!hdev)
2204 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2205 ENODEV);
2206
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002207 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208
2209 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2210 cp->randomizer);
2211 if (err < 0)
2212 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2213 else
2214 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2215 0);
2216
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002217 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 hci_dev_put(hdev);
2219
2220 return err;
2221}
2222
2223static int remove_remote_oob_data(struct sock *sk, u16 index,
2224 unsigned char *data, u16 len)
2225{
2226 struct hci_dev *hdev;
2227 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2228 int err;
2229
2230 BT_DBG("hci%u ", index);
2231
2232 if (len != sizeof(*cp))
2233 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2234 EINVAL);
2235
2236 hdev = hci_dev_get(index);
2237 if (!hdev)
2238 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2239 ENODEV);
2240
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002241 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
2243 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2244 if (err < 0)
2245 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2246 -err);
2247 else
2248 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2249 NULL, 0);
2250
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002251 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002252 hci_dev_put(hdev);
2253
2254 return err;
2255}
2256
Johan Hedberg03811012010-12-08 00:21:06 +02002257int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2258{
2259 unsigned char *buf;
2260 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002261 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002262 int err;
2263
2264 BT_DBG("got %zu bytes", msglen);
2265
2266 if (msglen < sizeof(*hdr))
2267 return -EINVAL;
2268
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002269 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002270 if (!buf)
2271 return -ENOMEM;
2272
2273 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2274 err = -EFAULT;
2275 goto done;
2276 }
2277
2278 hdr = (struct mgmt_hdr *) buf;
2279 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002280 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002281 len = get_unaligned_le16(&hdr->len);
2282
2283 if (len != msglen - sizeof(*hdr)) {
2284 err = -EINVAL;
2285 goto done;
2286 }
2287
Brian Gixa68668b2011-08-11 15:49:36 -07002288 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002289 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002290 case MGMT_OP_READ_VERSION:
2291 err = read_version(sk);
2292 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002293 case MGMT_OP_READ_INDEX_LIST:
2294 err = read_index_list(sk);
2295 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002296 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002297 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002298 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002299 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002300 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002301 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002302 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002303 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002304 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002305 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2306 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2307 len);
2308 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002309 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002310 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002311 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002312 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002313 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002314 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002315 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002316 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002317 break;
2318 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002319 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002320 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002321 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002322 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002323 break;
2324 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002325 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002326 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002327 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002328 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002329 break;
2330 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002331 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002332 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002333 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002334 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002335 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002336 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002337 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002338 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002339 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002340 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002341 break;
2342 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002343 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002344 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002345 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002346 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002347 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002348 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002349 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002350 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002351 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002352 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002353 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002354 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2355 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002356 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002357 case MGMT_OP_SET_LOCAL_NAME:
2358 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2359 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002360 case MGMT_OP_START_DISCOVERY:
2361 err = start_discovery(sk, index);
2362 break;
2363 case MGMT_OP_STOP_DISCOVERY:
2364 err = stop_discovery(sk, index);
2365 break;
2366 case MGMT_OP_RESOLVE_NAME:
2367 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2368 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002369 case MGMT_OP_SET_CONNECTION_PARAMS:
2370 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2371 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002372 case MGMT_OP_READ_LOCAL_OOB_DATA:
2373 err = read_local_oob_data(sk, index);
2374 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002375 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2376 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2377 break;
2378 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2379 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2380 len);
2381 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302382 case MGMT_OP_ENCRYPT_LINK:
2383 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2384 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385
Johan Hedberg03811012010-12-08 00:21:06 +02002386 default:
2387 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002388 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002389 break;
2390 }
2391
Johan Hedberge41d8b42010-12-13 21:07:03 +02002392 if (err < 0)
2393 goto done;
2394
Johan Hedberg03811012010-12-08 00:21:06 +02002395 err = msglen;
2396
2397done:
2398 kfree(buf);
2399 return err;
2400}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002401
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002402int mgmt_index_added(u16 index)
2403{
Brian Gixa68668b2011-08-11 15:49:36 -07002404 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002405 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002406}
2407
2408int mgmt_index_removed(u16 index)
2409{
Brian Gixa68668b2011-08-11 15:49:36 -07002410 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002411 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002412}
2413
Johan Hedberg73f22f62010-12-29 16:00:25 +02002414struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002415 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002416 struct sock *sk;
2417};
2418
Johan Hedberg72a734e2010-12-30 00:38:22 +02002419static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002420{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002421 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002422 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002423
Johan Hedberg72a734e2010-12-30 00:38:22 +02002424 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002425 return;
2426
Johan Hedberg053f0212011-01-26 13:07:10 +02002427 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002428
2429 list_del(&cmd->list);
2430
2431 if (match->sk == NULL) {
2432 match->sk = cmd->sk;
2433 sock_hold(match->sk);
2434 }
2435
2436 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002437}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002438
2439int mgmt_powered(u16 index, u8 powered)
2440{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002441 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002442 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002443 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002444
Brian Gixa68668b2011-08-11 15:49:36 -07002445 BT_DBG("hci%u %d", index, powered);
2446
Johan Hedberg72a734e2010-12-30 00:38:22 +02002447 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002448
Johan Hedberg72a734e2010-12-30 00:38:22 +02002449 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002450
Szymon Janc4e51eae2011-02-25 19:05:48 +01002451 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002452
2453 if (match.sk)
2454 sock_put(match.sk);
2455
2456 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002457}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002458
Johan Hedberg73f22f62010-12-29 16:00:25 +02002459int mgmt_discoverable(u16 index, u8 discoverable)
2460{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002461 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002462 struct cmd_lookup match = { discoverable, NULL };
2463 int ret;
2464
Szymon Jancb8534e02011-03-01 16:55:34 +01002465 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002466
Johan Hedberg72a734e2010-12-30 00:38:22 +02002467 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002468
Szymon Janc4e51eae2011-02-25 19:05:48 +01002469 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2470 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002471
2472 if (match.sk)
2473 sock_put(match.sk);
2474
2475 return ret;
2476}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002477
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002478int mgmt_connectable(u16 index, u8 connectable)
2479{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002480 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002481 struct cmd_lookup match = { connectable, NULL };
2482 int ret;
2483
Johan Hedberg72a734e2010-12-30 00:38:22 +02002484 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002485
Johan Hedberg72a734e2010-12-30 00:38:22 +02002486 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002487
Szymon Janc4e51eae2011-02-25 19:05:48 +01002488 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002489
2490 if (match.sk)
2491 sock_put(match.sk);
2492
2493 return ret;
2494}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002495
Brian Gixa68668b2011-08-11 15:49:36 -07002496int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002497{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002498 struct mgmt_ev_new_key *ev;
2499 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002500
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002501 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2502 ev = kzalloc(total, GFP_ATOMIC);
2503 if (!ev)
2504 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002505
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002506 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002507 ev->key.addr_type = key->addr_type;
2508 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002509 memcpy(ev->key.val, key->val, 16);
2510 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002511 ev->key.auth = key->auth;
2512 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002513 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002514
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002515 memcpy(ev->key.data, key->data, key->dlen);
2516
2517 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2518
2519 kfree(ev);
2520
2521 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002522}
Johan Hedbergf7520542011-01-20 12:34:39 +02002523
Brian Gix2e2f50d2011-09-13 12:36:04 -07002524int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002525{
2526 struct mgmt_ev_connected ev;
2527
Johan Hedbergf7520542011-01-20 12:34:39 +02002528 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002529 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002530
Szymon Janc4e51eae2011-02-25 19:05:48 +01002531 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002532}
2533
Johan Hedberg8962ee72011-01-20 12:40:27 +02002534static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2535{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002536 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002537 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002538 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002539
Johan Hedberga38528f2011-01-22 06:46:43 +02002540 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002541
Szymon Janc4e51eae2011-02-25 19:05:48 +01002542 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002543
2544 *sk = cmd->sk;
2545 sock_hold(*sk);
2546
Johan Hedberga664b5b2011-02-19 12:06:02 -03002547 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002548}
2549
Johan Hedbergf7520542011-01-20 12:34:39 +02002550int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2551{
2552 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002553 struct sock *sk = NULL;
2554 int err;
2555
2556 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002557
Johan Hedbergf7520542011-01-20 12:34:39 +02002558 bacpy(&ev.bdaddr, bdaddr);
2559
Szymon Janc4e51eae2011-02-25 19:05:48 +01002560 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002561
2562 if (sk)
2563 sock_put(sk);
2564
2565 return err;
2566}
2567
2568int mgmt_disconnect_failed(u16 index)
2569{
2570 struct pending_cmd *cmd;
2571 int err;
2572
2573 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2574 if (!cmd)
2575 return -ENOENT;
2576
Szymon Janc4e51eae2011-02-25 19:05:48 +01002577 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002578
Johan Hedberga664b5b2011-02-19 12:06:02 -03002579 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002580
2581 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002582}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002583
2584int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2585{
2586 struct mgmt_ev_connect_failed ev;
2587
Johan Hedberg17d5c042011-01-22 06:09:08 +02002588 bacpy(&ev.bdaddr, bdaddr);
2589 ev.status = status;
2590
Szymon Janc4e51eae2011-02-25 19:05:48 +01002591 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002592}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002595{
2596 struct mgmt_ev_pin_code_request ev;
2597
Brian Gixa68668b2011-08-11 15:49:36 -07002598 BT_DBG("hci%u", index);
2599
Johan Hedberg980e1a52011-01-22 06:10:07 +02002600 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002601 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002602
Szymon Janc4e51eae2011-02-25 19:05:48 +01002603 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2604 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002605}
2606
2607int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2608{
2609 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002610 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002611 int err;
2612
2613 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2614 if (!cmd)
2615 return -ENOENT;
2616
Johan Hedbergac56fb12011-02-19 12:05:59 -03002617 bacpy(&rp.bdaddr, bdaddr);
2618 rp.status = status;
2619
Szymon Janc4e51eae2011-02-25 19:05:48 +01002620 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2621 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002622
Johan Hedberga664b5b2011-02-19 12:06:02 -03002623 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002624
2625 return err;
2626}
2627
2628int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2629{
2630 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002631 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002632 int err;
2633
2634 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2635 if (!cmd)
2636 return -ENOENT;
2637
Johan Hedbergac56fb12011-02-19 12:05:59 -03002638 bacpy(&rp.bdaddr, bdaddr);
2639 rp.status = status;
2640
Szymon Janc4e51eae2011-02-25 19:05:48 +01002641 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2642 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002643
Johan Hedberga664b5b2011-02-19 12:06:02 -03002644 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002645
2646 return err;
2647}
Johan Hedberga5c29682011-02-19 12:05:57 -03002648
Brian Gixa68668b2011-08-11 15:49:36 -07002649int mgmt_user_confirm_request(u16 index, u8 event,
2650 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002651{
2652 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002653 struct hci_conn *conn = NULL;
2654 struct hci_dev *hdev;
2655 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2656
2657 BT_DBG("hci%u", index);
2658
2659 hdev = hci_dev_get(index);
2660
Brian Gix64bd5302011-09-08 11:35:48 -07002661 if (!hdev)
2662 return -ENODEV;
2663
Brian Gix64bd5302011-09-08 11:35:48 -07002664 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002665
2666 ev.auto_confirm = 0;
2667
2668 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2669 goto no_auto_confirm;
2670
2671 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2672 rem_cap = conn->remote_cap;
2673 loc_mitm = conn->auth_type & 0x01;
2674 rem_mitm = conn->remote_auth & 0x01;
2675
Brian Gixdbf59292011-11-11 15:45:17 -08002676 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2677 conn->auth_initiator && rem_cap == 0x03)
2678 ev.auto_confirm = 1;
2679 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
Brian Gixa68668b2011-08-11 15:49:36 -07002680 goto no_auto_confirm;
2681
2682
2683 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2684 ev.auto_confirm = 1;
2685
2686no_auto_confirm:
2687 bacpy(&ev.bdaddr, bdaddr);
2688 ev.event = event;
2689 put_unaligned_le32(value, &ev.value);
2690
Brian Gix64bd5302011-09-08 11:35:48 -07002691 hci_dev_put(hdev);
2692
Brian Gixa68668b2011-08-11 15:49:36 -07002693 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2694 NULL);
2695}
2696
2697int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2698{
2699 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002700
2701 BT_DBG("hci%u", index);
2702
Johan Hedberga5c29682011-02-19 12:05:57 -03002703 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002704
Brian Gixa68668b2011-08-11 15:49:36 -07002705 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002706 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002707}
2708
2709static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2710 u8 opcode)
2711{
2712 struct pending_cmd *cmd;
2713 struct mgmt_rp_user_confirm_reply rp;
2714 int err;
2715
2716 cmd = mgmt_pending_find(opcode, index);
2717 if (!cmd)
2718 return -ENOENT;
2719
Johan Hedberga5c29682011-02-19 12:05:57 -03002720 bacpy(&rp.bdaddr, bdaddr);
2721 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002722 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002723
Johan Hedberga664b5b2011-02-19 12:06:02 -03002724 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002725
2726 return err;
2727}
2728
2729int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2730{
2731 return confirm_reply_complete(index, bdaddr, status,
2732 MGMT_OP_USER_CONFIRM_REPLY);
2733}
2734
Szymon Jancb8534e02011-03-01 16:55:34 +01002735int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002736{
2737 return confirm_reply_complete(index, bdaddr, status,
2738 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2739}
Johan Hedberg2a611692011-02-19 12:06:00 -03002740
2741int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2742{
2743 struct mgmt_ev_auth_failed ev;
2744
Johan Hedberg2a611692011-02-19 12:06:00 -03002745 bacpy(&ev.bdaddr, bdaddr);
2746 ev.status = status;
2747
Szymon Janc4e51eae2011-02-25 19:05:48 +01002748 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002749}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002750
2751int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2752{
2753 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002754 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002755 struct mgmt_cp_set_local_name ev;
2756 int err;
2757
2758 memset(&ev, 0, sizeof(ev));
2759 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2760
2761 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2762 if (!cmd)
2763 goto send_event;
2764
2765 if (status) {
2766 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2767 goto failed;
2768 }
2769
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002770 hdev = hci_dev_get(index);
2771 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002772 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002773 hci_dev_put(hdev);
2774 }
2775
Johan Hedbergb312b1612011-03-16 14:29:37 +02002776 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2777 sizeof(ev));
2778 if (err < 0)
2779 goto failed;
2780
2781send_event:
2782 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2783 cmd ? cmd->sk : NULL);
2784
2785failed:
2786 if (cmd)
2787 mgmt_pending_remove(cmd);
2788 return err;
2789}
Szymon Jancc35938b2011-03-22 13:12:21 +01002790
2791int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2792 u8 status)
2793{
2794 struct pending_cmd *cmd;
2795 int err;
2796
2797 BT_DBG("hci%u status %u", index, status);
2798
2799 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2800 if (!cmd)
2801 return -ENOENT;
2802
2803 if (status) {
2804 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2805 EIO);
2806 } else {
2807 struct mgmt_rp_read_local_oob_data rp;
2808
2809 memcpy(rp.hash, hash, sizeof(rp.hash));
2810 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2811
2812 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2813 &rp, sizeof(rp));
2814 }
2815
2816 mgmt_pending_remove(cmd);
2817
2818 return err;
2819}
Johan Hedberge17acd42011-03-30 23:57:16 +03002820
Brian Gixa68668b2011-08-11 15:49:36 -07002821int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2822 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002823{
2824 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002825 struct pending_cmd *cmd;
2826 int err;
2827
2828 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002829
2830 memset(&ev, 0, sizeof(ev));
2831
2832 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002833 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002834 ev.type = type;
2835 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002836
Brian Gixa68668b2011-08-11 15:49:36 -07002837 if (dev_class)
2838 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002839
Brian Gixa68668b2011-08-11 15:49:36 -07002840 if (eir && eir_len)
2841 memcpy(ev.eir, eir, eir_len);
2842
2843 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2844
2845 if (err < 0)
2846 return err;
2847
2848 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2849 if (cmd) {
2850 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002851 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002852
2853 ilp->int_count++;
2854 if (hdev && ilp->int_count >= ilp->int_phase) {
2855 /* Inquiry scan for General Discovery LAP */
2856 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2857 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002858
Brian Gixa68668b2011-08-11 15:49:36 -07002859 ilp->int_phase *= 2;
2860 ilp->int_count = 0;
2861 if (ilp->mode == SCAN_LE) {
2862 /* cancel LE scan */
2863 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2864 sizeof(le_cp), &le_cp);
2865 /* start BR scan */
2866 cp.num_rsp = (u8) ilp->int_phase;
2867 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2868 sizeof(cp), &cp);
2869 ilp->mode = SCAN_BR;
Brian Gix6e349d02011-11-28 14:51:14 -08002870 del_timer_sync(&hdev->disc_le_timer);
Brian Gixa68668b2011-08-11 15:49:36 -07002871 }
2872 }
Brian Gix64bd5302011-09-08 11:35:48 -07002873
2874 if (hdev)
2875 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002876 }
2877
2878 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002879}
Johan Hedberga88a9652011-03-30 13:18:12 +03002880
Brian Gixa68668b2011-08-11 15:49:36 -07002881
2882int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002883{
2884 struct mgmt_ev_remote_name ev;
2885
2886 memset(&ev, 0, sizeof(ev));
2887
2888 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002889 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002890 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2891
2892 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2893}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302894
2895int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
2896{
2897 struct mgmt_ev_encrypt_change ev;
2898
2899 BT_DBG("hci%u", index);
2900
2901 bacpy(&ev.bdaddr, bdaddr);
2902 ev.status = status;
2903
2904 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
2905 NULL);
2906}
2907