blob: ea7270852d1513b72301fe180689735c616f1d01 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
Brian Gixa68668b2011-08-11 15:49:36 -070030#include <net/bluetooth/l2cap.h>
Johan Hedberg03811012010-12-08 00:21:06 +020031#include <net/bluetooth/mgmt.h>
Brian Gixa68668b2011-08-11 15:49:36 -070032#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020033
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Brian Gixa68668b2011-08-11 15:49:36 -070037enum scan_mode {
38 SCAN_IDLE,
39 SCAN_LE,
40 SCAN_BR
41};
42
43struct disco_interleave {
44 struct timer_list timer;
45 struct timer_list le_timer;
46 u16 index;
47 enum scan_mode mode;
48 int int_phase;
49 int int_count;
50};
51
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020052struct pending_cmd {
53 struct list_head list;
54 __u16 opcode;
55 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010056 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020057 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030058 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020059};
60
Mat Martineau8cd0df02011-08-23 16:23:36 -070061struct mgmt_pending_free_work {
62 struct work_struct work;
63 struct sock *sk;
64};
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020067
Szymon Janc4e51eae2011-02-25 19:05:48 +010068static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020069{
70 struct sk_buff *skb;
71 struct mgmt_hdr *hdr;
72 struct mgmt_ev_cmd_status *ev;
73
Szymon Janc34eb5252011-02-28 14:10:08 +010074 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020075
76 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
77 if (!skb)
78 return -ENOMEM;
79
80 hdr = (void *) skb_put(skb, sizeof(*hdr));
81
82 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010083 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020084 hdr->len = cpu_to_le16(sizeof(*ev));
85
86 ev = (void *) skb_put(skb, sizeof(*ev));
87 ev->status = status;
88 put_unaligned_le16(cmd, &ev->opcode);
89
90 if (sock_queue_rcv_skb(sk, skb) < 0)
91 kfree_skb(skb);
92
93 return 0;
94}
95
Szymon Janc4e51eae2011-02-25 19:05:48 +010096static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
97 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020098{
99 struct sk_buff *skb;
100 struct mgmt_hdr *hdr;
101 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +0200102
103 BT_DBG("sock %p", sk);
104
Johan Hedberga38528f2011-01-22 06:46:43 +0200105 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 if (!skb)
107 return -ENOMEM;
108
109 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200110
Johan Hedberg02d98122010-12-13 21:07:04 +0200111 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100112 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200113 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200114
Johan Hedberga38528f2011-01-22 06:46:43 +0200115 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
116 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100117
118 if (rp)
119 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200120
121 if (sock_queue_rcv_skb(sk, skb) < 0)
122 kfree_skb(skb);
123
124 return 0;
125}
126
Johan Hedberga38528f2011-01-22 06:46:43 +0200127static int read_version(struct sock *sk)
128{
129 struct mgmt_rp_read_version rp;
130
131 BT_DBG("sock %p", sk);
132
133 rp.version = MGMT_VERSION;
134 put_unaligned_le16(MGMT_REVISION, &rp.revision);
135
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
137 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200138}
139
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140static int read_index_list(struct sock *sk)
141{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142 struct mgmt_rp_read_index_list *rp;
143 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200144 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200145 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200146 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147
148 BT_DBG("sock %p", sk);
149
150 read_lock(&hci_dev_list_lock);
151
152 count = 0;
153 list_for_each(p, &hci_dev_list) {
Peter Krystad1fc44072011-08-30 15:38:12 -0700154 struct hci_dev *d = list_entry(p, struct hci_dev, list);
155 if (d->dev_type != HCI_BREDR)
156 continue;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200157 count++;
158 }
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 rp_len = sizeof(*rp) + (2 * count);
161 rp = kmalloc(rp_len, GFP_ATOMIC);
162 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100163 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200164 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100165 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166
Brian Gixa68668b2011-08-11 15:49:36 -0700167 put_unaligned_le16(0, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200168
169 i = 0;
170 list_for_each(p, &hci_dev_list) {
171 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200172
173 hci_del_off_timer(d);
174
Peter Krystad1fc44072011-08-30 15:38:12 -0700175 if (d->dev_type != HCI_BREDR)
176 continue;
177
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200178 set_bit(HCI_MGMT, &d->flags);
179
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200180 if (test_bit(HCI_SETUP, &d->flags))
181 continue;
182
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200183 put_unaligned_le16(d->id, &rp->index[i++]);
Brian Gixa68668b2011-08-11 15:49:36 -0700184 put_unaligned_le16((u16)i, &rp->num_controllers);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200185 BT_DBG("Added hci%u", d->id);
186 }
187
188 read_unlock(&hci_dev_list_lock);
189
Szymon Janc4e51eae2011-02-25 19:05:48 +0100190 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
191 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 kfree(rp);
194
195 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200199{
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200202
Szymon Janc4e51eae2011-02-25 19:05:48 +0100203 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200204
Szymon Janc4e51eae2011-02-25 19:05:48 +0100205 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100207 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200209 hci_del_off_timer(hdev);
210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200213 set_bit(HCI_MGMT, &hdev->flags);
214
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200215 memset(&rp, 0, sizeof(rp));
216
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218
Johan Hedberga38528f2011-01-22 06:46:43 +0200219 rp.powered = test_bit(HCI_UP, &hdev->flags);
220 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
221 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
222 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223
224 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200225 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200227 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200229 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200230
Johan Hedberga38528f2011-01-22 06:46:43 +0200231 bacpy(&rp.bdaddr, &hdev->bdaddr);
232 memcpy(rp.features, hdev->features, 8);
233 memcpy(rp.dev_class, hdev->dev_class, 3);
234 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
235 rp.hci_ver = hdev->hci_ver;
236 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200237
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200238 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200241 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200242
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200244}
245
Mat Martineau8cd0df02011-08-23 16:23:36 -0700246static void mgmt_pending_free_worker(struct work_struct *work)
247{
248 struct mgmt_pending_free_work *free_work =
249 container_of(work, struct mgmt_pending_free_work, work);
250
251 BT_DBG("sk %p", free_work->sk);
252
253 sock_put(free_work->sk);
254 kfree(free_work);
255}
256
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200257static void mgmt_pending_free(struct pending_cmd *cmd)
258{
Mat Martineau8cd0df02011-08-23 16:23:36 -0700259 struct mgmt_pending_free_work *free_work;
260 struct sock *sk = cmd->sk;
Brian Gixa68668b2011-08-11 15:49:36 -0700261
Mat Martineau8cd0df02011-08-23 16:23:36 -0700262 BT_DBG("opcode %d, sk %p", cmd->opcode, sk);
263
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100264 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200265 kfree(cmd);
Mat Martineau8cd0df02011-08-23 16:23:36 -0700266
267 free_work = kzalloc(sizeof(*free_work), GFP_ATOMIC);
268 if (free_work) {
269 INIT_WORK(&free_work->work, mgmt_pending_free_worker);
270 free_work->sk = sk;
271
272 if (!schedule_work(&free_work->work))
273 kfree(free_work);
274 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200275}
276
Johan Hedberg366a0332011-02-19 12:05:55 -0300277static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
278 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200279{
280 struct pending_cmd *cmd;
281
Brian Gixa68668b2011-08-11 15:49:36 -0700282 BT_DBG("%d", opcode);
283
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200284 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
285 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300286 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200287
288 cmd->opcode = opcode;
289 cmd->index = index;
290
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100291 cmd->param = kmalloc(len, GFP_ATOMIC);
292 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200293 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300294 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200295 }
296
Szymon Janc8fce6352011-03-22 13:12:20 +0100297 if (data)
298 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299
300 cmd->sk = sk;
301 sock_hold(sk);
302
303 list_add(&cmd->list, &cmd_list);
304
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306}
307
308static void mgmt_pending_foreach(u16 opcode, int index,
309 void (*cb)(struct pending_cmd *cmd, void *data),
310 void *data)
311{
312 struct list_head *p, *n;
313
Brian Gixa68668b2011-08-11 15:49:36 -0700314 BT_DBG(" %d", opcode);
315
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 list_for_each_safe(p, n, &cmd_list) {
317 struct pending_cmd *cmd;
318
319 cmd = list_entry(p, struct pending_cmd, list);
320
321 if (cmd->opcode != opcode)
322 continue;
323
324 if (index >= 0 && cmd->index != index)
325 continue;
326
327 cb(cmd, data);
328 }
329}
330
331static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
332{
333 struct list_head *p;
334
Brian Gixa68668b2011-08-11 15:49:36 -0700335 BT_DBG(" %d", opcode);
336
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337 list_for_each(p, &cmd_list) {
338 struct pending_cmd *cmd;
339
340 cmd = list_entry(p, struct pending_cmd, list);
341
342 if (cmd->opcode != opcode)
343 continue;
344
345 if (index >= 0 && cmd->index != index)
346 continue;
347
348 return cmd;
349 }
350
351 return NULL;
352}
353
Johan Hedberga664b5b2011-02-19 12:06:02 -0300354static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355{
Brian Gixa68668b2011-08-11 15:49:36 -0700356 BT_DBG(" %d", cmd->opcode);
357
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 list_del(&cmd->list);
359 mgmt_pending_free(cmd);
360}
361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200363{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200364 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200365 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300366 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300367 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200368
369 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200370
Szymon Janc4e51eae2011-02-25 19:05:48 +0100371 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200372
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100373 if (len != sizeof(*cp))
374 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
375
Szymon Janc4e51eae2011-02-25 19:05:48 +0100376 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200381
382 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200383 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100384 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200385 goto failed;
386 }
387
Szymon Janc4e51eae2011-02-25 19:05:48 +0100388 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
389 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200390 goto failed;
391 }
392
Szymon Janc4e51eae2011-02-25 19:05:48 +0100393 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 if (!cmd) {
395 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300397 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200400 queue_work(hdev->workqueue, &hdev->power_on);
401 else
402 queue_work(hdev->workqueue, &hdev->power_off);
403
Johan Hedberg366a0332011-02-19 12:05:55 -0300404 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200405
406failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200408 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300409 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200410}
411
Brian Gix8a7f1642011-10-17 17:39:46 -0700412static u8 get_service_classes(struct hci_dev *hdev)
413{
414 struct list_head *p;
415 u8 val = 0;
416
417 list_for_each(p, &hdev->uuids) {
418 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
419
420 val |= uuid->svc_hint;
421 }
422
423 return val;
424}
425
426static int update_class(struct hci_dev *hdev)
427{
428 u8 cod[3];
429
430 BT_DBG("%s", hdev->name);
431
432 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
433 return 0;
434
435 cod[0] = hdev->minor_class;
436 cod[1] = hdev->major_class;
437 cod[2] = get_service_classes(hdev);
438
439 if (memcmp(cod, hdev->dev_class, 3) == 0)
440 return 0;
441
442 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
443}
444
445static int set_limited_discoverable(struct sock *sk, u16 index,
446 unsigned char *data, u16 len)
447{
448 struct mgmt_mode *cp;
449 struct hci_dev *hdev;
450 struct pending_cmd *cmd;
451 struct hci_cp_write_current_iac_lap dcp;
452 int update_cod;
453 int err = 0;
454 /* General Inquiry LAP: 0x9E8B33, Limited Inquiry LAP: 0x9E8B00 */
455 u8 lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
456
457 cp = (void *) data;
458
459 BT_DBG("hci%u discoverable: %d", index, cp->val);
460
461 if (!cp || len != sizeof(*cp))
462 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
463 EINVAL);
464
465 hdev = hci_dev_get(index);
466 if (!hdev)
467 return cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
468 ENODEV);
469
470 hci_dev_lock(hdev);
471
472 if (!test_bit(HCI_UP, &hdev->flags)) {
473 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
474 ENETDOWN);
475 goto failed;
476 }
477
478 if (mgmt_pending_find(MGMT_OP_SET_LIMIT_DISCOVERABLE, index)) {
479 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
480 EBUSY);
481 goto failed;
482 }
483
484 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
485 test_bit(HCI_PSCAN, &hdev->flags)) {
486 err = cmd_status(sk, index, MGMT_OP_SET_LIMIT_DISCOVERABLE,
487 EALREADY);
488 goto failed;
489 }
490
491 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LIMIT_DISCOVERABLE, index, data,
492 len);
493 if (!cmd) {
494 err = -ENOMEM;
495 goto failed;
496 }
497
498 memset(&dcp, 0, sizeof(dcp));
499 dcp.num_current_iac = cp->val ? 2 : 1;
500 memcpy(&dcp.lap, lap, dcp.num_current_iac * 3);
501 update_cod = 1;
502
503 if (cp->val) {
504 if (hdev->major_class & MGMT_MAJOR_CLASS_LIMITED)
505 update_cod = 0;
506 hdev->major_class |= MGMT_MAJOR_CLASS_LIMITED;
507 } else {
508 if (!(hdev->major_class & MGMT_MAJOR_CLASS_LIMITED))
509 update_cod = 0;
510 hdev->major_class &= ~MGMT_MAJOR_CLASS_LIMITED;
511 }
512
513 if (update_cod)
514 err = update_class(hdev);
515
516 if (err >= 0)
517 err = hci_send_cmd(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
518 sizeof(dcp), &dcp);
519
520 if (err < 0)
521 mgmt_pending_remove(cmd);
522
523failed:
524 hci_dev_unlock(hdev);
525 hci_dev_put(hdev);
526
527 return err;
528}
529
Szymon Janc4e51eae2011-02-25 19:05:48 +0100530static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
531 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200532{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200533 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200534 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300535 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200536 u8 scan;
537 int err;
538
539 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200540
Szymon Janc4e51eae2011-02-25 19:05:48 +0100541 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200542
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100543 if (len != sizeof(*cp))
544 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
545
Szymon Janc4e51eae2011-02-25 19:05:48 +0100546 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200547 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100548 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200551
552 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100553 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200554 goto failed;
555 }
556
Szymon Janc4e51eae2011-02-25 19:05:48 +0100557 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
558 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
559 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200560 goto failed;
561 }
562
Johan Hedberg72a734e2010-12-30 00:38:22 +0200563 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200564 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100565 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200566 goto failed;
567 }
568
Szymon Janc4e51eae2011-02-25 19:05:48 +0100569 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300570 if (!cmd) {
571 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200572 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300573 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200574
575 scan = SCAN_PAGE;
576
Johan Hedberg72a734e2010-12-30 00:38:22 +0200577 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200578 scan |= SCAN_INQUIRY;
579
580 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
581 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300582 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200583
584failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200586 hci_dev_put(hdev);
587
588 return err;
589}
590
Szymon Janc4e51eae2011-02-25 19:05:48 +0100591static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
592 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200593{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200594 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200595 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300596 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200597 u8 scan;
598 int err;
599
600 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200601
Szymon Janc4e51eae2011-02-25 19:05:48 +0100602 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200603
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100604 if (len != sizeof(*cp))
605 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
606
Szymon Janc4e51eae2011-02-25 19:05:48 +0100607 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200608 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100609 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200612
613 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100614 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200615 goto failed;
616 }
617
Szymon Janc4e51eae2011-02-25 19:05:48 +0100618 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
619 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
620 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200621 goto failed;
622 }
623
Johan Hedberg72a734e2010-12-30 00:38:22 +0200624 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100625 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200626 goto failed;
627 }
628
Szymon Janc4e51eae2011-02-25 19:05:48 +0100629 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300630 if (!cmd) {
631 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200632 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300633 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200634
Johan Hedberg72a734e2010-12-30 00:38:22 +0200635 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200636 scan = SCAN_PAGE;
637 else
638 scan = 0;
639
640 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
641 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300642 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200643
644failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200646 hci_dev_put(hdev);
647
648 return err;
649}
650
Szymon Janc4e51eae2011-02-25 19:05:48 +0100651static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
652 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200653{
654 struct sk_buff *skb;
655 struct mgmt_hdr *hdr;
656
Brian Gixa68668b2011-08-11 15:49:36 -0700657 BT_DBG("hci%d %d", index, event);
658
Johan Hedbergc542a062011-01-26 13:11:03 +0200659 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
660 if (!skb)
661 return -ENOMEM;
662
663 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
664
665 hdr = (void *) skb_put(skb, sizeof(*hdr));
666 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100667 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200668 hdr->len = cpu_to_le16(data_len);
669
Szymon Janc4e51eae2011-02-25 19:05:48 +0100670 if (data)
671 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200672
673 hci_send_to_sock(NULL, skb, skip_sk);
674 kfree_skb(skb);
675
676 return 0;
677}
678
Johan Hedberg053f0212011-01-26 13:07:10 +0200679static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
680{
Johan Hedberga38528f2011-01-22 06:46:43 +0200681 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200682
Johan Hedberga38528f2011-01-22 06:46:43 +0200683 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200684
Szymon Janc4e51eae2011-02-25 19:05:48 +0100685 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200686}
687
Szymon Janc4e51eae2011-02-25 19:05:48 +0100688static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
689 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200690{
691 struct mgmt_mode *cp, ev;
692 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200693 int err;
694
695 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200696
Szymon Janc4e51eae2011-02-25 19:05:48 +0100697 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200698
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100699 if (len != sizeof(*cp))
700 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
701
Szymon Janc4e51eae2011-02-25 19:05:48 +0100702 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200703 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100704 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200707
708 if (cp->val)
709 set_bit(HCI_PAIRABLE, &hdev->flags);
710 else
711 clear_bit(HCI_PAIRABLE, &hdev->flags);
712
Szymon Janc4e51eae2011-02-25 19:05:48 +0100713 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200714 if (err < 0)
715 goto failed;
716
Johan Hedbergc542a062011-01-26 13:11:03 +0200717 ev.val = cp->val;
718
Szymon Janc4e51eae2011-02-25 19:05:48 +0100719 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200720
721failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200723 hci_dev_put(hdev);
724
725 return err;
726}
727
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300728#define EIR_FLAGS 0x01 /* flags */
729#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
730#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
731#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
732#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
733#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
734#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
735#define EIR_NAME_SHORT 0x08 /* shortened local name */
736#define EIR_NAME_COMPLETE 0x09 /* complete local name */
737#define EIR_TX_POWER 0x0A /* transmit power level */
738#define EIR_DEVICE_ID 0x10 /* device ID */
739
740#define PNP_INFO_SVCLASS_ID 0x1200
741
742static u8 bluetooth_base_uuid[] = {
743 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
744 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
745};
746
747static u16 get_uuid16(u8 *uuid128)
748{
749 u32 val;
750 int i;
751
752 for (i = 0; i < 12; i++) {
753 if (bluetooth_base_uuid[i] != uuid128[i])
754 return 0;
755 }
756
757 memcpy(&val, &uuid128[12], 4);
758
759 val = le32_to_cpu(val);
760 if (val > 0xffff)
761 return 0;
762
763 return (u16) val;
764}
765
766static void create_eir(struct hci_dev *hdev, u8 *data)
767{
768 u8 *ptr = data;
769 u16 eir_len = 0;
770 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
771 int i, truncated = 0;
772 struct list_head *p;
773 size_t name_len;
774
775 name_len = strlen(hdev->dev_name);
776
777 if (name_len > 0) {
778 /* EIR Data type */
779 if (name_len > 48) {
780 name_len = 48;
781 ptr[1] = EIR_NAME_SHORT;
782 } else
783 ptr[1] = EIR_NAME_COMPLETE;
784
785 /* EIR Data length */
786 ptr[0] = name_len + 1;
787
788 memcpy(ptr + 2, hdev->dev_name, name_len);
789
790 eir_len += (name_len + 2);
791 ptr += (name_len + 2);
792 }
793
794 memset(uuid16_list, 0, sizeof(uuid16_list));
795
796 /* Group all UUID16 types */
797 list_for_each(p, &hdev->uuids) {
798 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
799 u16 uuid16;
800
801 uuid16 = get_uuid16(uuid->uuid);
802 if (uuid16 == 0)
803 return;
804
805 if (uuid16 < 0x1100)
806 continue;
807
808 if (uuid16 == PNP_INFO_SVCLASS_ID)
809 continue;
810
811 /* Stop if not enough space to put next UUID */
812 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
813 truncated = 1;
814 break;
815 }
816
817 /* Check for duplicates */
818 for (i = 0; uuid16_list[i] != 0; i++)
819 if (uuid16_list[i] == uuid16)
820 break;
821
822 if (uuid16_list[i] == 0) {
823 uuid16_list[i] = uuid16;
824 eir_len += sizeof(u16);
825 }
826 }
827
828 if (uuid16_list[0] != 0) {
829 u8 *length = ptr;
830
831 /* EIR Data type */
832 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
833
834 ptr += 2;
835 eir_len += 2;
836
837 for (i = 0; uuid16_list[i] != 0; i++) {
838 *ptr++ = (uuid16_list[i] & 0x00ff);
839 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
840 }
841
842 /* EIR Data length */
843 *length = (i * sizeof(u16)) + 1;
844 }
845}
846
847static int update_eir(struct hci_dev *hdev)
848{
849 struct hci_cp_write_eir cp;
850
851 if (!(hdev->features[6] & LMP_EXT_INQ))
852 return 0;
853
854 if (hdev->ssp_mode == 0)
855 return 0;
856
857 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
858 return 0;
859
860 memset(&cp, 0, sizeof(cp));
861
862 create_eir(hdev, cp.data);
863
864 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
865 return 0;
866
867 memcpy(hdev->eir, cp.data, sizeof(cp.data));
868
869 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
870}
871
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200873{
874 struct mgmt_cp_add_uuid *cp;
875 struct hci_dev *hdev;
876 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200877 int err;
878
879 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200880
Szymon Janc4e51eae2011-02-25 19:05:48 +0100881 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200882
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100883 if (len != sizeof(*cp))
884 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
885
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200891
892 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
893 if (!uuid) {
894 err = -ENOMEM;
895 goto failed;
896 }
897
898 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200900
901 list_add(&uuid->list, &hdev->uuids);
902
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200903 err = update_class(hdev);
904 if (err < 0)
905 goto failed;
906
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300907 err = update_eir(hdev);
908 if (err < 0)
909 goto failed;
910
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200912
913failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915 hci_dev_put(hdev);
916
917 return err;
918}
919
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200921{
922 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100923 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924 struct hci_dev *hdev;
925 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 +0200926 int err, found;
927
928 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200931
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100932 if (len != sizeof(*cp))
933 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
934
Szymon Janc4e51eae2011-02-25 19:05:48 +0100935 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200936 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100937 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200940
941 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
942 err = hci_uuids_clear(hdev);
943 goto unlock;
944 }
945
946 found = 0;
947
948 list_for_each_safe(p, n, &hdev->uuids) {
949 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
950
951 if (memcmp(match->uuid, cp->uuid, 16) != 0)
952 continue;
953
954 list_del(&match->list);
955 found++;
956 }
957
958 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200960 goto unlock;
961 }
962
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200963 err = update_class(hdev);
964 if (err < 0)
965 goto unlock;
966
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300967 err = update_eir(hdev);
968 if (err < 0)
969 goto unlock;
970
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200972
973unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200975 hci_dev_put(hdev);
976
977 return err;
978}
979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
981 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200982{
983 struct hci_dev *hdev;
984 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200985 int err;
986
987 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988
Szymon Janc4e51eae2011-02-25 19:05:48 +0100989 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200990
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100991 if (len != sizeof(*cp))
992 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
993
Szymon Janc4e51eae2011-02-25 19:05:48 +0100994 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200995 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100996 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200999
Brian Gix8a7f1642011-10-17 17:39:46 -07001000 hdev->major_class &= ~MGMT_MAJOR_CLASS_MASK;
1001 hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002 hdev->minor_class = cp->minor;
1003
1004 err = update_class(hdev);
1005
1006 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001010 hci_dev_put(hdev);
1011
1012 return err;
1013}
1014
Szymon Janc4e51eae2011-02-25 19:05:48 +01001015static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1016 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017{
1018 struct hci_dev *hdev;
1019 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001020 int err;
1021
1022 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001023
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001024 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001025 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001026
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001028 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001034
1035 if (cp->enable) {
1036 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1037 err = 0;
1038 } else {
1039 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
1040 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001041 if (err == 0)
1042 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001043 }
1044
1045 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001046 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1047 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001050 hci_dev_put(hdev);
1051
1052 return err;
1053}
1054
Szymon Janc4e51eae2011-02-25 19:05:48 +01001055static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001056{
1057 struct hci_dev *hdev;
1058 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001059 u16 key_count, expected_len;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001060 int i, err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001061
1062 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001063
1064 if (len < sizeof(*cp))
1065 return -EINVAL;
1066
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001067 key_count = get_unaligned_le16(&cp->key_count);
1068
1069 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001070 if (expected_len > len) {
1071 BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
1072 expected_len, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001073 return -EINVAL;
1074 }
1075
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001077 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001079
Szymon Janc4e51eae2011-02-25 19:05:48 +01001080 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001081 key_count);
1082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001084
1085 hci_link_keys_clear(hdev);
1086
1087 set_bit(HCI_LINK_KEYS, &hdev->flags);
1088
1089 if (cp->debug_keys)
1090 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1091 else
1092 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1093
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001094 len -= sizeof(*cp);
1095 i = 0;
1096
1097 while (i < len) {
1098 struct mgmt_key_info *key = (void *) cp->keys + i;
1099
Brian Gixa68668b2011-08-11 15:49:36 -07001100 i += sizeof(*key);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 if (key->type == KEY_TYPE_LTK) {
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001103 struct key_master_id *id = (void *) key->data;
1104
1105 if (key->dlen != sizeof(struct key_master_id))
1106 continue;
1107
Vinicius Costa Gomes1fa2de32011-07-08 18:31:45 -03001108 hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
Brian Gixa68668b2011-08-11 15:49:36 -07001109 key->auth, id->ediv, id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001110
1111 continue;
1112 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001115 key->pin_len);
1116 }
1117
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001118 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001121 hci_dev_put(hdev);
1122
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001123 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001124}
1125
Szymon Janc4e51eae2011-02-25 19:05:48 +01001126static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127{
1128 struct hci_dev *hdev;
1129 struct mgmt_cp_remove_key *cp;
1130 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001131 int err;
1132
1133 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001134
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001135 if (len != sizeof(*cp))
1136 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1137
Szymon Janc4e51eae2011-02-25 19:05:48 +01001138 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001139 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001140 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001143
1144 err = hci_remove_link_key(hdev, &cp->bdaddr);
1145 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001146 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001147 goto unlock;
1148 }
1149
1150 err = 0;
1151
1152 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1153 goto unlock;
1154
1155 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1156 if (conn) {
1157 struct hci_cp_disconnect dc;
1158
1159 put_unaligned_le16(conn->handle, &dc.handle);
1160 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001162 }
1163
1164unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001166 hci_dev_put(hdev);
1167
1168 return err;
1169}
1170
Szymon Janc4e51eae2011-02-25 19:05:48 +01001171static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001172{
1173 struct hci_dev *hdev;
1174 struct mgmt_cp_disconnect *cp;
1175 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001176 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001178 int err;
1179
1180 BT_DBG("");
1181
1182 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001183
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001184 if (len != sizeof(*cp))
1185 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1186
Szymon Janc4e51eae2011-02-25 19:05:48 +01001187 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001189 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001192
1193 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001194 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195 goto failed;
1196 }
1197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1199 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001200 goto failed;
1201 }
1202
1203 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1204 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001205 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1206 if (!conn) {
1207 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1208 ENOTCONN);
1209 goto failed;
1210 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001211 }
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001214 if (!cmd) {
1215 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001216 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001217 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218
1219 put_unaligned_le16(conn->handle, &dc.handle);
1220 dc.reason = 0x13; /* Remote User Terminated Connection */
1221
1222 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1223 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001224 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001225
1226failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001228 hci_dev_put(hdev);
1229
1230 return err;
1231}
1232
Szymon Janc8ce62842011-03-01 16:55:32 +01001233static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001234{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001235 struct mgmt_rp_get_connections *rp;
1236 struct hci_dev *hdev;
1237 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001238 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001240 int i, err;
1241
1242 BT_DBG("");
1243
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001245 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249
1250 count = 0;
1251 list_for_each(p, &hdev->conn_hash.list) {
1252 count++;
1253 }
1254
Johan Hedberga38528f2011-01-22 06:46:43 +02001255 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1256 rp = kmalloc(rp_len, GFP_ATOMIC);
1257 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001258 err = -ENOMEM;
1259 goto unlock;
1260 }
1261
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262 put_unaligned_le16(count, &rp->conn_count);
1263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 read_lock(&hci_dev_list_lock);
1265
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266 i = 0;
1267 list_for_each(p, &hdev->conn_hash.list) {
1268 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1269
1270 bacpy(&rp->conn[i++], &c->dst);
1271 }
1272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 read_unlock(&hci_dev_list_lock);
1274
Szymon Janc4e51eae2011-02-25 19:05:48 +01001275 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001276
1277unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001278 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001280 hci_dev_put(hdev);
1281 return err;
1282}
1283
Szymon Janc4e51eae2011-02-25 19:05:48 +01001284static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1285 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001286{
1287 struct hci_dev *hdev;
1288 struct mgmt_cp_pin_code_reply *cp;
1289 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001290 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001291 int err;
1292
1293 BT_DBG("");
1294
1295 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001296
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001297 if (len != sizeof(*cp))
1298 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1299
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001301 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001302 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001305
1306 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001308 goto failed;
1309 }
1310
Szymon Janc4e51eae2011-02-25 19:05:48 +01001311 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001312 if (!cmd) {
1313 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001315 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001316
1317 bacpy(&reply.bdaddr, &cp->bdaddr);
1318 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320
1321 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1322 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001323 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324
1325failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001327 hci_dev_put(hdev);
1328
1329 return err;
1330}
1331
Szymon Janc4e51eae2011-02-25 19:05:48 +01001332static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1333 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334{
1335 struct hci_dev *hdev;
1336 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338 int err;
1339
1340 BT_DBG("");
1341
1342 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001343
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001344 if (len != sizeof(*cp))
1345 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1346 EINVAL);
1347
Szymon Janc4e51eae2011-02-25 19:05:48 +01001348 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001349 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001350 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1351 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001354
1355 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001356 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1357 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001358 goto failed;
1359 }
1360
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1362 data, len);
1363 if (!cmd) {
1364 err = -ENOMEM;
1365 goto failed;
1366 }
1367
1368 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1369 &cp->bdaddr);
1370 if (err < 0)
1371 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372
1373failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001375 hci_dev_put(hdev);
1376
1377 return err;
1378}
1379
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1381 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001382{
1383 struct hci_dev *hdev;
1384 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001385
1386 BT_DBG("");
1387
1388 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001389
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001390 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001391 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001392
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001394 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001395 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001398
1399 hdev->io_capability = cp->io_capability;
1400
1401 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001402 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001405 hci_dev_put(hdev);
1406
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001408}
1409
Johan Hedberge9a416b2011-02-19 12:05:56 -03001410static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1411{
1412 struct hci_dev *hdev = conn->hdev;
1413 struct list_head *p;
1414
1415 list_for_each(p, &cmd_list) {
1416 struct pending_cmd *cmd;
1417
1418 cmd = list_entry(p, struct pending_cmd, list);
1419
1420 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1421 continue;
1422
1423 if (cmd->index != hdev->id)
1424 continue;
1425
1426 if (cmd->user_data != conn)
1427 continue;
1428
1429 return cmd;
1430 }
1431
1432 return NULL;
1433}
1434
1435static void pairing_complete(struct pending_cmd *cmd, u8 status)
1436{
1437 struct mgmt_rp_pair_device rp;
1438 struct hci_conn *conn = cmd->user_data;
1439
Brian Gixa68668b2011-08-11 15:49:36 -07001440 BT_DBG(" %u", status);
1441
Johan Hedberge9a416b2011-02-19 12:05:56 -03001442 bacpy(&rp.bdaddr, &conn->dst);
1443 rp.status = status;
1444
Szymon Janc4e51eae2011-02-25 19:05:48 +01001445 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446
1447 /* So we don't get further callbacks for this connection */
1448 conn->connect_cfm_cb = NULL;
1449 conn->security_cfm_cb = NULL;
1450 conn->disconn_cfm_cb = NULL;
1451
Johan Hedberga664b5b2011-02-19 12:06:02 -03001452 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001453}
1454
1455static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1456{
1457 struct pending_cmd *cmd;
1458
Brian Gixa68668b2011-08-11 15:49:36 -07001459 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001460
1461 cmd = find_pairing(conn);
1462 if (!cmd) {
1463 BT_DBG("Unable to find a pending command");
1464 return;
1465 }
1466
1467 pairing_complete(cmd, status);
1468}
1469
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001470static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001471{
1472 struct pending_cmd *cmd;
1473
1474 BT_DBG(" %u", status);
1475
1476 cmd = find_pairing(conn);
1477 if (!cmd) {
1478 BT_DBG("Unable to find a pending command");
1479 return;
1480 }
1481
1482 if (conn->type == LE_LINK)
1483 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1484 status ? 0 : 1);
1485 else
1486 pairing_complete(cmd, status);
1487}
1488
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001489static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001490{
1491 struct pending_cmd *cmd;
1492
1493 BT_DBG("conn: %p %u", conn, status);
1494
1495 cmd = find_pairing(conn);
1496 if (!cmd) {
1497 BT_DBG("Unable to find a pending command");
1498 return;
1499 }
Brian Gix114f3a62011-09-27 14:02:20 -07001500
1501 if (status)
1502 pairing_complete(cmd, status);
1503
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001504 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001505}
1506
1507static void discovery_terminated(struct pending_cmd *cmd, void *data)
1508{
1509 struct mgmt_mode ev = {0};
1510 struct disco_interleave *ilp = cmd->param;
1511
1512 BT_DBG("");
1513 del_timer_sync(&ilp->le_timer);
1514 del_timer_sync(&ilp->timer);
1515 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1516
1517 list_del(&cmd->list);
1518
1519 mgmt_pending_free(cmd);
1520}
1521
Szymon Janc4e51eae2011-02-25 19:05:48 +01001522static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001523{
1524 struct hci_dev *hdev;
1525 struct mgmt_cp_pair_device *cp;
1526 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001527 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001528 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001529 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001530 int err;
1531
1532 BT_DBG("");
1533
Brian Gix64bd5302011-09-08 11:35:48 -07001534 cp = (void *) data;
1535
1536 if (len != sizeof(*cp))
1537 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1538
Szymon Janc4e51eae2011-02-25 19:05:48 +01001539 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001540
Johan Hedberge9a416b2011-02-19 12:05:56 -03001541 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001542 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001545
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301546 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1547 io_cap = cp->io_cap;
1548 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001549 sec_level = BT_SECURITY_MEDIUM;
1550 auth_type = HCI_AT_DEDICATED_BONDING;
1551 } else {
1552 sec_level = BT_SECURITY_HIGH;
1553 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1554 }
1555
Brian Gixfdd38922011-09-28 16:23:48 -07001556 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1557 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001558 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1559 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001560 } else {
1561 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1562 if (io_cap == 0x04)
1563 io_cap = 0x01;
1564 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1565 auth_type);
1566 }
1567
Ville Tervo30e76272011-02-22 16:10:53 -03001568 if (IS_ERR(conn)) {
1569 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001570 goto unlock;
1571 }
1572
1573 if (conn->connect_cfm_cb) {
1574 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001575 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001576 goto unlock;
1577 }
1578
Szymon Janc4e51eae2011-02-25 19:05:48 +01001579 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001580 if (!cmd) {
1581 err = -ENOMEM;
1582 hci_conn_put(conn);
1583 goto unlock;
1584 }
1585
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001586 conn->connect_cfm_cb = pairing_connect_complete_cb;
1587 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001588 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001589 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001590 cmd->user_data = conn;
1591
1592 if (conn->state == BT_CONNECTED &&
1593 hci_conn_security(conn, sec_level, auth_type))
1594 pairing_complete(cmd, 0);
1595
1596 err = 0;
1597
1598unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001600 hci_dev_put(hdev);
1601
1602 return err;
1603}
1604
Szymon Janc4e51eae2011-02-25 19:05:48 +01001605static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001606 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001607{
1608 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001609 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001610 struct pending_cmd *cmd;
1611 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001612 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001613 int err;
1614
Brian Gixa68668b2011-08-11 15:49:36 -07001615 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001616
Brian Gixa68668b2011-08-11 15:49:36 -07001617 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001618 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001619 else
1620 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001621
Brian Gixa68668b2011-08-11 15:49:36 -07001622 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001623 return cmd_status(sk, index, mgmt_op, EINVAL);
1624
Szymon Janc4e51eae2011-02-25 19:05:48 +01001625 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001626 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001627 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001630
Johan Hedberga5c29682011-02-19 12:05:57 -03001631 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001632 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001633 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001634 }
1635
Brian Gixa68668b2011-08-11 15:49:36 -07001636 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1637 if (le_conn) {
1638 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1639 goto done;
1640 }
1641 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1642 "Reject" : "Accept");
1643
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001645 if (!cmd) {
1646 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001647 goto done;
1648 }
1649
1650 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1651 if (err < 0)
1652 mgmt_pending_remove(cmd);
1653
1654done:
1655 hci_dev_unlock(hdev);
1656 hci_dev_put(hdev);
1657
1658 return err;
1659}
1660
1661static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1662 u16 len)
1663{
1664 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1665 struct hci_cp_remote_name_req hci_cp;
1666 struct hci_dev *hdev;
1667 struct pending_cmd *cmd;
1668 int err;
1669
1670 BT_DBG("");
1671
1672 if (len != sizeof(*mgmt_cp))
1673 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1674
1675 hdev = hci_dev_get(index);
1676 if (!hdev)
1677 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1678
1679 hci_dev_lock(hdev);
1680
1681 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1682 if (!cmd) {
1683 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001684 goto failed;
1685 }
1686
Brian Gixa68668b2011-08-11 15:49:36 -07001687 memset(&hci_cp, 0, sizeof(hci_cp));
1688 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1689 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1690 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001691 if (err < 0)
1692 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001693
1694failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001696 hci_dev_put(hdev);
1697
1698 return err;
1699}
1700
Johan Hedbergb312b1612011-03-16 14:29:37 +02001701static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1702 u16 len)
1703{
1704 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1705 struct hci_cp_write_local_name hci_cp;
1706 struct hci_dev *hdev;
1707 struct pending_cmd *cmd;
1708 int err;
1709
1710 BT_DBG("");
1711
1712 if (len != sizeof(*mgmt_cp))
1713 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1714
1715 hdev = hci_dev_get(index);
1716 if (!hdev)
1717 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001720
1721 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1722 if (!cmd) {
1723 err = -ENOMEM;
1724 goto failed;
1725 }
1726
1727 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1728 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1729 &hci_cp);
1730 if (err < 0)
1731 mgmt_pending_remove(cmd);
1732
1733failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001735 hci_dev_put(hdev);
1736
1737 return err;
1738}
1739
Brian Gixa68668b2011-08-11 15:49:36 -07001740static void discovery_rsp(struct pending_cmd *cmd, void *data)
1741{
1742 struct mgmt_mode ev;
1743
1744 BT_DBG("");
1745 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1746 ev.val = 1;
1747 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1748 } else {
1749 ev.val = 0;
1750 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1751 NULL, 0);
1752 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1753 struct disco_interleave *ilp = cmd->param;
1754
1755 del_timer_sync(&ilp->le_timer);
1756 del_timer_sync(&ilp->timer);
1757 }
1758 }
1759
1760 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1761
1762 list_del(&cmd->list);
1763
1764 mgmt_pending_free(cmd);
1765}
1766
1767void mgmt_inquiry_started(u16 index)
1768{
1769 BT_DBG("");
1770 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1771 discovery_rsp, NULL);
1772}
1773
1774void mgmt_inquiry_complete_evt(u16 index, u8 status)
1775{
1776 struct hci_dev *hdev;
1777 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1778 struct pending_cmd *cmd;
1779 int err = -1;
1780
1781 BT_DBG("");
1782
1783 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001784
1785 if (hdev)
1786 hci_dev_lock(hdev);
1787
Brian Gixa68668b2011-08-11 15:49:36 -07001788 if (!hdev || !lmp_le_capable(hdev)) {
1789 struct mgmt_mode cp = {0};
1790
1791 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1792 discovery_terminated, NULL);
1793
1794 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001795
Brian Gix64bd5302011-09-08 11:35:48 -07001796 if (hdev)
1797 goto done;
1798 else
1799 return;
1800 }
Brian Gixa68668b2011-08-11 15:49:36 -07001801
1802 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1803 if (cmd && cmd->param) {
1804 struct disco_interleave *ilp = cmd->param;
1805
1806 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1807 sizeof(le_cp), &le_cp);
1808 if (err >= 0) {
1809 mod_timer(&ilp->le_timer, jiffies +
1810 msecs_to_jiffies(ilp->int_phase * 1000));
1811 ilp->mode = SCAN_LE;
1812 } else
1813 ilp->mode = SCAN_IDLE;
1814 }
1815
1816 if (err < 0)
1817 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1818 discovery_terminated, NULL);
1819
Brian Gix64bd5302011-09-08 11:35:48 -07001820done:
Brian Gixa68668b2011-08-11 15:49:36 -07001821 hci_dev_unlock(hdev);
1822 hci_dev_put(hdev);
1823}
1824
1825static void disco_to(unsigned long data)
1826{
1827 struct disco_interleave *ilp = (void *)data;
1828 struct hci_dev *hdev;
1829 struct pending_cmd *cmd;
1830
1831 BT_DBG("hci%d", ilp->index);
1832
1833 del_timer_sync(&ilp->le_timer);
1834 hdev = hci_dev_get(ilp->index);
1835
1836 if (hdev) {
1837 hci_dev_lock(hdev);
1838
1839 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1840
1841 if (ilp->mode != SCAN_IDLE) {
1842 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1843
1844 if (ilp->mode == SCAN_LE)
1845 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1846 sizeof(le_cp), &le_cp);
1847 else
1848 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1849 0, NULL);
1850
1851 ilp->mode = SCAN_IDLE;
1852 }
1853
1854 if (cmd) {
1855 struct mgmt_mode cp = {0};
1856
1857 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1858 sizeof(cp), NULL);
1859 mgmt_pending_remove(cmd);
1860 }
1861
1862 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001863 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001864 }
1865}
1866
1867static void disco_le_to(unsigned long data)
1868{
1869 struct disco_interleave *ilp = (void *)data;
1870 struct hci_dev *hdev;
1871 struct pending_cmd *cmd;
1872 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1873
1874 BT_DBG("hci%d", ilp->index);
1875
1876 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001877
1878 if (hdev) {
1879 hci_dev_lock(hdev);
1880
1881 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1882
1883 if (ilp->mode == SCAN_LE)
1884 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1885 sizeof(le_cp), &le_cp);
1886
1887 /* re-start BR scan */
1888 if (cmd) {
1889 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1890 ilp->int_phase *= 2;
1891 ilp->int_count = 0;
1892 cp.num_rsp = (u8) ilp->int_phase;
1893 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1894 ilp->mode = SCAN_BR;
1895 } else
1896 ilp->mode = SCAN_IDLE;
1897
1898 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001899 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001900 }
1901}
1902
1903static int start_discovery(struct sock *sk, u16 index)
1904{
1905 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1906 struct hci_dev *hdev;
1907 struct pending_cmd *cmd;
1908 int err;
1909
1910 BT_DBG("");
1911
1912 hdev = hci_dev_get(index);
1913 if (!hdev)
1914 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1915
1916 hci_dev_lock(hdev);
1917
1918 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1919 if (!cmd) {
1920 err = -ENOMEM;
1921 goto failed;
1922 }
1923
1924 /* If LE Capable, we will alternate between BR/EDR and LE */
1925 if (lmp_le_capable(hdev)) {
1926 struct hci_cp_le_set_scan_parameters le_cp;
1927
1928 /* Shorten BR scan params */
1929 cp.num_rsp = 1;
1930 cp.length /= 2;
1931
1932 /* Setup LE scan params */
1933 memset(&le_cp, 0, sizeof(le_cp));
1934 le_cp.type = 0x01; /* Active scanning */
1935 /* The recommended value for scan interval and window is
1936 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1937 le_cp.interval = cpu_to_le16(0x0012);
1938 le_cp.window = cpu_to_le16(0x0012);
1939 le_cp.own_bdaddr_type = 0; /* Public address */
1940 le_cp.filter = 0; /* Accept all adv packets */
1941
1942 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1943 sizeof(le_cp), &le_cp);
1944 }
1945
1946 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1947
1948 if (err < 0)
1949 mgmt_pending_remove(cmd);
1950 else if (lmp_le_capable(hdev)) {
1951 struct disco_interleave il, *ilp;
1952
1953 il.int_phase = 1;
1954 il.int_count = 0;
1955 il.index = index;
1956 il.mode = SCAN_BR;
1957 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1958 sizeof(struct disco_interleave));
1959 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1960 if (cmd) {
1961 ilp = cmd->param;
1962 setup_timer(&ilp->le_timer, disco_le_to,
1963 (unsigned long) ilp);
1964 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1965 mod_timer(&ilp->timer,
1966 jiffies + msecs_to_jiffies(20000));
1967 }
1968 }
1969
1970failed:
1971 hci_dev_unlock(hdev);
1972 hci_dev_put(hdev);
1973
1974 return err;
1975}
1976
1977static int stop_discovery(struct sock *sk, u16 index)
1978{
1979 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1980 struct mgmt_mode mode_cp = {0};
1981 struct disco_interleave *ilp = NULL;
1982 struct hci_dev *hdev;
1983 struct pending_cmd *cmd = NULL;
1984 int err = -EPERM;
1985
1986 BT_DBG("");
1987
1988 hdev = hci_dev_get(index);
1989 if (!hdev)
1990 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1991
1992 hci_dev_lock(hdev);
1993
1994 if (lmp_le_capable(hdev)) {
1995 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1996 if (!cmd) {
1997 err = -ENOMEM;
1998 goto failed;
1999 }
2000
2001 ilp = cmd->param;
2002 }
2003
2004 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2005 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2006 sizeof(le_cp), &le_cp);
2007
2008 if (err < 0) {
2009 if (!ilp || (ilp->mode == SCAN_BR))
2010 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2011 0, NULL);
2012 }
2013
2014 if (ilp) {
2015 ilp->mode = SCAN_IDLE;
2016 del_timer_sync(&ilp->le_timer);
2017 del_timer_sync(&ilp->timer);
2018 }
2019
2020 if (err < 0 && cmd)
2021 mgmt_pending_remove(cmd);
2022
2023 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2024
2025failed:
2026 hci_dev_unlock(hdev);
2027 hci_dev_put(hdev);
2028
2029 if (err < 0)
2030 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2031 else
2032 return err;
2033}
2034
Szymon Jancc35938b2011-03-22 13:12:21 +01002035static int read_local_oob_data(struct sock *sk, u16 index)
2036{
2037 struct hci_dev *hdev;
2038 struct pending_cmd *cmd;
2039 int err;
2040
2041 BT_DBG("hci%u", index);
2042
2043 hdev = hci_dev_get(index);
2044 if (!hdev)
2045 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2046 ENODEV);
2047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002049
2050 if (!test_bit(HCI_UP, &hdev->flags)) {
2051 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2052 ENETDOWN);
2053 goto unlock;
2054 }
2055
2056 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2057 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2058 EOPNOTSUPP);
2059 goto unlock;
2060 }
2061
2062 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2063 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2064 goto unlock;
2065 }
2066
2067 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2068 if (!cmd) {
2069 err = -ENOMEM;
2070 goto unlock;
2071 }
2072
2073 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2074 if (err < 0)
2075 mgmt_pending_remove(cmd);
2076
2077unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002079 hci_dev_put(hdev);
2080
2081 return err;
2082}
2083
Szymon Janc2763eda2011-03-22 13:12:22 +01002084static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2085 u16 len)
2086{
2087 struct hci_dev *hdev;
2088 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2089 int err;
2090
2091 BT_DBG("hci%u ", index);
2092
2093 if (len != sizeof(*cp))
2094 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2095 EINVAL);
2096
2097 hdev = hci_dev_get(index);
2098 if (!hdev)
2099 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2100 ENODEV);
2101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002103
2104 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2105 cp->randomizer);
2106 if (err < 0)
2107 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2108 else
2109 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2110 0);
2111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002113 hci_dev_put(hdev);
2114
2115 return err;
2116}
2117
2118static int remove_remote_oob_data(struct sock *sk, u16 index,
2119 unsigned char *data, u16 len)
2120{
2121 struct hci_dev *hdev;
2122 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2123 int err;
2124
2125 BT_DBG("hci%u ", index);
2126
2127 if (len != sizeof(*cp))
2128 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2129 EINVAL);
2130
2131 hdev = hci_dev_get(index);
2132 if (!hdev)
2133 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2134 ENODEV);
2135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002137
2138 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2139 if (err < 0)
2140 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2141 -err);
2142 else
2143 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2144 NULL, 0);
2145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002147 hci_dev_put(hdev);
2148
2149 return err;
2150}
2151
Johan Hedberg03811012010-12-08 00:21:06 +02002152int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2153{
2154 unsigned char *buf;
2155 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002157 int err;
2158
2159 BT_DBG("got %zu bytes", msglen);
2160
2161 if (msglen < sizeof(*hdr))
2162 return -EINVAL;
2163
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002164 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002165 if (!buf)
2166 return -ENOMEM;
2167
2168 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2169 err = -EFAULT;
2170 goto done;
2171 }
2172
2173 hdr = (struct mgmt_hdr *) buf;
2174 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002175 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002176 len = get_unaligned_le16(&hdr->len);
2177
2178 if (len != msglen - sizeof(*hdr)) {
2179 err = -EINVAL;
2180 goto done;
2181 }
2182
Brian Gixa68668b2011-08-11 15:49:36 -07002183 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002184 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002185 case MGMT_OP_READ_VERSION:
2186 err = read_version(sk);
2187 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002188 case MGMT_OP_READ_INDEX_LIST:
2189 err = read_index_list(sk);
2190 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002191 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002192 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002193 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002194 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002195 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002196 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002197 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002198 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002199 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002200 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2201 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2202 len);
2203 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002204 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002205 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002206 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002207 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002208 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002209 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002210 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002211 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002212 break;
2213 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002214 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002215 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002216 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002217 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002218 break;
2219 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002220 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002221 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002222 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002223 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002224 break;
2225 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002226 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002227 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002228 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002229 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002230 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002231 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002232 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002233 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002234 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002235 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002236 break;
2237 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002238 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002239 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002240 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002241 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002242 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002243 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002244 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002245 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002246 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002247 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002248 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002249 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2250 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002251 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002252 case MGMT_OP_SET_LOCAL_NAME:
2253 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2254 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002255 case MGMT_OP_START_DISCOVERY:
2256 err = start_discovery(sk, index);
2257 break;
2258 case MGMT_OP_STOP_DISCOVERY:
2259 err = stop_discovery(sk, index);
2260 break;
2261 case MGMT_OP_RESOLVE_NAME:
2262 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2263 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002264 case MGMT_OP_READ_LOCAL_OOB_DATA:
2265 err = read_local_oob_data(sk, index);
2266 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002267 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2268 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2269 break;
2270 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2271 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2272 len);
2273 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274
Johan Hedberg03811012010-12-08 00:21:06 +02002275 default:
2276 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002277 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002278 break;
2279 }
2280
Johan Hedberge41d8b42010-12-13 21:07:03 +02002281 if (err < 0)
2282 goto done;
2283
Johan Hedberg03811012010-12-08 00:21:06 +02002284 err = msglen;
2285
2286done:
2287 kfree(buf);
2288 return err;
2289}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002290
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002291int mgmt_index_added(u16 index)
2292{
Brian Gixa68668b2011-08-11 15:49:36 -07002293 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002294 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002295}
2296
2297int mgmt_index_removed(u16 index)
2298{
Brian Gixa68668b2011-08-11 15:49:36 -07002299 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002300 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002301}
2302
Johan Hedberg73f22f62010-12-29 16:00:25 +02002303struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002304 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002305 struct sock *sk;
2306};
2307
Johan Hedberg72a734e2010-12-30 00:38:22 +02002308static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002309{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002310 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002311 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002312
Johan Hedberg72a734e2010-12-30 00:38:22 +02002313 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002314 return;
2315
Johan Hedberg053f0212011-01-26 13:07:10 +02002316 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002317
2318 list_del(&cmd->list);
2319
2320 if (match->sk == NULL) {
2321 match->sk = cmd->sk;
2322 sock_hold(match->sk);
2323 }
2324
2325 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002326}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002327
2328int mgmt_powered(u16 index, u8 powered)
2329{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002330 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002331 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002332 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002333
Brian Gixa68668b2011-08-11 15:49:36 -07002334 BT_DBG("hci%u %d", index, powered);
2335
Johan Hedberg72a734e2010-12-30 00:38:22 +02002336 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002337
Johan Hedberg72a734e2010-12-30 00:38:22 +02002338 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002339
Szymon Janc4e51eae2011-02-25 19:05:48 +01002340 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002341
2342 if (match.sk)
2343 sock_put(match.sk);
2344
2345 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002346}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002347
Johan Hedberg73f22f62010-12-29 16:00:25 +02002348int mgmt_discoverable(u16 index, u8 discoverable)
2349{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002350 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002351 struct cmd_lookup match = { discoverable, NULL };
2352 int ret;
2353
Szymon Jancb8534e02011-03-01 16:55:34 +01002354 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002355
Johan Hedberg72a734e2010-12-30 00:38:22 +02002356 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002357
Szymon Janc4e51eae2011-02-25 19:05:48 +01002358 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2359 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002360
2361 if (match.sk)
2362 sock_put(match.sk);
2363
2364 return ret;
2365}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002366
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002367int mgmt_connectable(u16 index, u8 connectable)
2368{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002369 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002370 struct cmd_lookup match = { connectable, NULL };
2371 int ret;
2372
Johan Hedberg72a734e2010-12-30 00:38:22 +02002373 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002374
Johan Hedberg72a734e2010-12-30 00:38:22 +02002375 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002376
Szymon Janc4e51eae2011-02-25 19:05:48 +01002377 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002378
2379 if (match.sk)
2380 sock_put(match.sk);
2381
2382 return ret;
2383}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002384
Brian Gixa68668b2011-08-11 15:49:36 -07002385int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002386{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002387 struct mgmt_ev_new_key *ev;
2388 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002389
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002390 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2391 ev = kzalloc(total, GFP_ATOMIC);
2392 if (!ev)
2393 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002394
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002395 bacpy(&ev->key.bdaddr, &key->bdaddr);
2396 ev->key.type = key->type;
2397 memcpy(ev->key.val, key->val, 16);
2398 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002399 ev->key.auth = key->auth;
2400 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002401 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002402
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002403 memcpy(ev->key.data, key->data, key->dlen);
2404
2405 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2406
2407 kfree(ev);
2408
2409 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002410}
Johan Hedbergf7520542011-01-20 12:34:39 +02002411
Brian Gix2e2f50d2011-09-13 12:36:04 -07002412int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002413{
2414 struct mgmt_ev_connected ev;
2415
Johan Hedbergf7520542011-01-20 12:34:39 +02002416 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002417 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002418
Szymon Janc4e51eae2011-02-25 19:05:48 +01002419 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002420}
2421
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2423{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002424 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002425 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002426 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002427
Johan Hedberga38528f2011-01-22 06:46:43 +02002428 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429
Szymon Janc4e51eae2011-02-25 19:05:48 +01002430 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002431
2432 *sk = cmd->sk;
2433 sock_hold(*sk);
2434
Johan Hedberga664b5b2011-02-19 12:06:02 -03002435 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002436}
2437
Johan Hedbergf7520542011-01-20 12:34:39 +02002438int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2439{
2440 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002441 struct sock *sk = NULL;
2442 int err;
2443
2444 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002445
Johan Hedbergf7520542011-01-20 12:34:39 +02002446 bacpy(&ev.bdaddr, bdaddr);
2447
Szymon Janc4e51eae2011-02-25 19:05:48 +01002448 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002449
2450 if (sk)
2451 sock_put(sk);
2452
2453 return err;
2454}
2455
2456int mgmt_disconnect_failed(u16 index)
2457{
2458 struct pending_cmd *cmd;
2459 int err;
2460
2461 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2462 if (!cmd)
2463 return -ENOENT;
2464
Szymon Janc4e51eae2011-02-25 19:05:48 +01002465 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002466
Johan Hedberga664b5b2011-02-19 12:06:02 -03002467 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002468
2469 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002470}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002471
2472int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2473{
2474 struct mgmt_ev_connect_failed ev;
2475
Johan Hedberg17d5c042011-01-22 06:09:08 +02002476 bacpy(&ev.bdaddr, bdaddr);
2477 ev.status = status;
2478
Szymon Janc4e51eae2011-02-25 19:05:48 +01002479 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002480}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483{
2484 struct mgmt_ev_pin_code_request ev;
2485
Brian Gixa68668b2011-08-11 15:49:36 -07002486 BT_DBG("hci%u", index);
2487
Johan Hedberg980e1a52011-01-22 06:10:07 +02002488 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002489 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002490
Szymon Janc4e51eae2011-02-25 19:05:48 +01002491 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2492 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002493}
2494
2495int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2496{
2497 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002498 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002499 int err;
2500
2501 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2502 if (!cmd)
2503 return -ENOENT;
2504
Johan Hedbergac56fb12011-02-19 12:05:59 -03002505 bacpy(&rp.bdaddr, bdaddr);
2506 rp.status = status;
2507
Szymon Janc4e51eae2011-02-25 19:05:48 +01002508 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2509 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002510
Johan Hedberga664b5b2011-02-19 12:06:02 -03002511 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002512
2513 return err;
2514}
2515
2516int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2517{
2518 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002519 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002520 int err;
2521
2522 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2523 if (!cmd)
2524 return -ENOENT;
2525
Johan Hedbergac56fb12011-02-19 12:05:59 -03002526 bacpy(&rp.bdaddr, bdaddr);
2527 rp.status = status;
2528
Szymon Janc4e51eae2011-02-25 19:05:48 +01002529 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2530 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002531
Johan Hedberga664b5b2011-02-19 12:06:02 -03002532 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533
2534 return err;
2535}
Johan Hedberga5c29682011-02-19 12:05:57 -03002536
Brian Gixa68668b2011-08-11 15:49:36 -07002537int mgmt_user_confirm_request(u16 index, u8 event,
2538 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002539{
2540 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002541 struct hci_conn *conn = NULL;
2542 struct hci_dev *hdev;
2543 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2544
2545 BT_DBG("hci%u", index);
2546
2547 hdev = hci_dev_get(index);
2548
Brian Gix64bd5302011-09-08 11:35:48 -07002549 if (!hdev)
2550 return -ENODEV;
2551
Brian Gix64bd5302011-09-08 11:35:48 -07002552 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002553
2554 ev.auto_confirm = 0;
2555
2556 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2557 goto no_auto_confirm;
2558
2559 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2560 rem_cap = conn->remote_cap;
2561 loc_mitm = conn->auth_type & 0x01;
2562 rem_mitm = conn->remote_auth & 0x01;
2563
2564 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2565 goto no_auto_confirm;
2566
2567
2568 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2569 ev.auto_confirm = 1;
2570
2571no_auto_confirm:
2572 bacpy(&ev.bdaddr, bdaddr);
2573 ev.event = event;
2574 put_unaligned_le32(value, &ev.value);
2575
Brian Gix64bd5302011-09-08 11:35:48 -07002576 hci_dev_put(hdev);
2577
Brian Gixa68668b2011-08-11 15:49:36 -07002578 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2579 NULL);
2580}
2581
2582int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2583{
2584 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002585
2586 BT_DBG("hci%u", index);
2587
Johan Hedberga5c29682011-02-19 12:05:57 -03002588 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002589
Brian Gixa68668b2011-08-11 15:49:36 -07002590 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002591 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002592}
2593
2594static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2595 u8 opcode)
2596{
2597 struct pending_cmd *cmd;
2598 struct mgmt_rp_user_confirm_reply rp;
2599 int err;
2600
2601 cmd = mgmt_pending_find(opcode, index);
2602 if (!cmd)
2603 return -ENOENT;
2604
Johan Hedberga5c29682011-02-19 12:05:57 -03002605 bacpy(&rp.bdaddr, bdaddr);
2606 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002607 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002608
Johan Hedberga664b5b2011-02-19 12:06:02 -03002609 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002610
2611 return err;
2612}
2613
2614int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2615{
2616 return confirm_reply_complete(index, bdaddr, status,
2617 MGMT_OP_USER_CONFIRM_REPLY);
2618}
2619
Szymon Jancb8534e02011-03-01 16:55:34 +01002620int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002621{
2622 return confirm_reply_complete(index, bdaddr, status,
2623 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2624}
Johan Hedberg2a611692011-02-19 12:06:00 -03002625
2626int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2627{
2628 struct mgmt_ev_auth_failed ev;
2629
Johan Hedberg2a611692011-02-19 12:06:00 -03002630 bacpy(&ev.bdaddr, bdaddr);
2631 ev.status = status;
2632
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002634}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002635
2636int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2637{
2638 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002639 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002640 struct mgmt_cp_set_local_name ev;
2641 int err;
2642
2643 memset(&ev, 0, sizeof(ev));
2644 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2645
2646 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2647 if (!cmd)
2648 goto send_event;
2649
2650 if (status) {
2651 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2652 goto failed;
2653 }
2654
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002655 hdev = hci_dev_get(index);
2656 if (hdev) {
2657 hci_dev_lock_bh(hdev);
2658 update_eir(hdev);
2659 hci_dev_unlock_bh(hdev);
2660 hci_dev_put(hdev);
2661 }
2662
Johan Hedbergb312b1612011-03-16 14:29:37 +02002663 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2664 sizeof(ev));
2665 if (err < 0)
2666 goto failed;
2667
2668send_event:
2669 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2670 cmd ? cmd->sk : NULL);
2671
2672failed:
2673 if (cmd)
2674 mgmt_pending_remove(cmd);
2675 return err;
2676}
Szymon Jancc35938b2011-03-22 13:12:21 +01002677
2678int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2679 u8 status)
2680{
2681 struct pending_cmd *cmd;
2682 int err;
2683
2684 BT_DBG("hci%u status %u", index, status);
2685
2686 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2687 if (!cmd)
2688 return -ENOENT;
2689
2690 if (status) {
2691 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2692 EIO);
2693 } else {
2694 struct mgmt_rp_read_local_oob_data rp;
2695
2696 memcpy(rp.hash, hash, sizeof(rp.hash));
2697 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2698
2699 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2700 &rp, sizeof(rp));
2701 }
2702
2703 mgmt_pending_remove(cmd);
2704
2705 return err;
2706}
Johan Hedberge17acd42011-03-30 23:57:16 +03002707
Brian Gixa68668b2011-08-11 15:49:36 -07002708int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2709 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002710{
2711 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002712 struct pending_cmd *cmd;
2713 int err;
2714
2715 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002716
2717 memset(&ev, 0, sizeof(ev));
2718
2719 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002720 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002721 ev.type = type;
2722 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002723
Brian Gixa68668b2011-08-11 15:49:36 -07002724 if (dev_class)
2725 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002726
Brian Gixa68668b2011-08-11 15:49:36 -07002727 if (eir && eir_len)
2728 memcpy(ev.eir, eir, eir_len);
2729
2730 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2731
2732 if (err < 0)
2733 return err;
2734
2735 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2736 if (cmd) {
2737 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002738 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002739
2740 ilp->int_count++;
2741 if (hdev && ilp->int_count >= ilp->int_phase) {
2742 /* Inquiry scan for General Discovery LAP */
2743 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2744 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002745
Brian Gixa68668b2011-08-11 15:49:36 -07002746 ilp->int_phase *= 2;
2747 ilp->int_count = 0;
2748 if (ilp->mode == SCAN_LE) {
2749 /* cancel LE scan */
2750 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2751 sizeof(le_cp), &le_cp);
2752 /* start BR scan */
2753 cp.num_rsp = (u8) ilp->int_phase;
2754 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2755 sizeof(cp), &cp);
2756 ilp->mode = SCAN_BR;
2757 del_timer_sync(&ilp->le_timer);
2758 }
2759 }
Brian Gix64bd5302011-09-08 11:35:48 -07002760
2761 if (hdev)
2762 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002763 }
2764
2765 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002766}
Johan Hedberga88a9652011-03-30 13:18:12 +03002767
Brian Gixa68668b2011-08-11 15:49:36 -07002768
2769int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002770{
2771 struct mgmt_ev_remote_name ev;
2772
2773 memset(&ev, 0, sizeof(ev));
2774
2775 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002776 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002777 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2778
2779 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2780}