blob: 77845f214187b1889b0d2c880d894b74859db51d [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
Brian Gixcf956772011-10-20 15:18:51 -07001102 if (key->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
Brian Gixcf956772011-10-20 15:18:51 -07001108 hci_add_ltk(hdev, 0, &key->bdaddr, key->addr_type,
1109 key->pin_len, key->auth, id->ediv,
1110 id->rand, key->val);
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001111
1112 continue;
1113 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001114
Brian Gixcf956772011-10-20 15:18:51 -07001115 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->key_type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001116 key->pin_len);
1117 }
1118
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001119 err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
1120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001122 hci_dev_put(hdev);
1123
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03001124 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001125}
1126
Szymon Janc4e51eae2011-02-25 19:05:48 +01001127static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001128{
1129 struct hci_dev *hdev;
1130 struct mgmt_cp_remove_key *cp;
1131 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001132 int err;
1133
1134 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001135
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001136 if (len != sizeof(*cp))
1137 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
1138
Szymon Janc4e51eae2011-02-25 19:05:48 +01001139 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001140 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001141 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001144
1145 err = hci_remove_link_key(hdev, &cp->bdaddr);
1146 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001148 goto unlock;
1149 }
1150
1151 err = 0;
1152
1153 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
1154 goto unlock;
1155
1156 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1157 if (conn) {
1158 struct hci_cp_disconnect dc;
1159
1160 put_unaligned_le16(conn->handle, &dc.handle);
1161 dc.reason = 0x13; /* Remote User Terminated Connection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001163 }
1164
1165unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001167 hci_dev_put(hdev);
1168
1169 return err;
1170}
1171
Szymon Janc4e51eae2011-02-25 19:05:48 +01001172static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173{
1174 struct hci_dev *hdev;
1175 struct mgmt_cp_disconnect *cp;
1176 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001177 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001178 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001179 int err;
1180
1181 BT_DBG("");
1182
1183 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001184
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001185 if (len != sizeof(*cp))
1186 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1187
Szymon Janc4e51eae2011-02-25 19:05:48 +01001188 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001190 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001193
1194 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196 goto failed;
1197 }
1198
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1200 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001201 goto failed;
1202 }
1203
1204 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1205 if (!conn) {
Inga Stotlandbd6a49a2011-08-23 16:13:39 -07001206 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1207 if (!conn) {
1208 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1209 ENOTCONN);
1210 goto failed;
1211 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001212 }
1213
Szymon Janc4e51eae2011-02-25 19:05:48 +01001214 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001215 if (!cmd) {
1216 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001217 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001218 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001219
1220 put_unaligned_le16(conn->handle, &dc.handle);
1221 dc.reason = 0x13; /* Remote User Terminated Connection */
1222
1223 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1224 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001225 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001226
1227failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001229 hci_dev_put(hdev);
1230
1231 return err;
1232}
1233
Szymon Janc8ce62842011-03-01 16:55:32 +01001234static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001235{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001236 struct mgmt_rp_get_connections *rp;
1237 struct hci_dev *hdev;
1238 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001239 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001240 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001241 int i, err;
1242
1243 BT_DBG("");
1244
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001247 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001250
1251 count = 0;
1252 list_for_each(p, &hdev->conn_hash.list) {
1253 count++;
1254 }
1255
Johan Hedberga38528f2011-01-22 06:46:43 +02001256 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1257 rp = kmalloc(rp_len, GFP_ATOMIC);
1258 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259 err = -ENOMEM;
1260 goto unlock;
1261 }
1262
Johan Hedberg2784eb42011-01-21 13:56:35 +02001263 put_unaligned_le16(count, &rp->conn_count);
1264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 read_lock(&hci_dev_list_lock);
1266
Johan Hedberg2784eb42011-01-21 13:56:35 +02001267 i = 0;
1268 list_for_each(p, &hdev->conn_hash.list) {
1269 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1270
1271 bacpy(&rp->conn[i++], &c->dst);
1272 }
1273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 read_unlock(&hci_dev_list_lock);
1275
Szymon Janc4e51eae2011-02-25 19:05:48 +01001276 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001277
1278unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001279 kfree(rp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001281 hci_dev_put(hdev);
1282 return err;
1283}
1284
Szymon Janc4e51eae2011-02-25 19:05:48 +01001285static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1286 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001287{
1288 struct hci_dev *hdev;
1289 struct mgmt_cp_pin_code_reply *cp;
1290 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001291 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001292 int err;
1293
1294 BT_DBG("");
1295
1296 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001298 if (len != sizeof(*cp))
1299 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1300
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001306
1307 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001308 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001309 goto failed;
1310 }
1311
Szymon Janc4e51eae2011-02-25 19:05:48 +01001312 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001313 if (!cmd) {
1314 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001316 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317
1318 bacpy(&reply.bdaddr, &cp->bdaddr);
1319 reply.pin_len = cp->pin_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320 memcpy(reply.pin_code, cp->pin_code, 16);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001321
1322 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1323 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001324 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001325
1326failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328 hci_dev_put(hdev);
1329
1330 return err;
1331}
1332
Szymon Janc4e51eae2011-02-25 19:05:48 +01001333static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1334 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001335{
1336 struct hci_dev *hdev;
1337 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339 int err;
1340
1341 BT_DBG("");
1342
1343 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001344
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001345 if (len != sizeof(*cp))
1346 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1347 EINVAL);
1348
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001351 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1352 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001355
1356 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001357 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1358 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001359 goto failed;
1360 }
1361
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1363 data, len);
1364 if (!cmd) {
1365 err = -ENOMEM;
1366 goto failed;
1367 }
1368
1369 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1370 &cp->bdaddr);
1371 if (err < 0)
1372 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001373
1374failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001376 hci_dev_put(hdev);
1377
1378 return err;
1379}
1380
Szymon Janc4e51eae2011-02-25 19:05:48 +01001381static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1382 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001383{
1384 struct hci_dev *hdev;
1385 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001386
1387 BT_DBG("");
1388
1389 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001390
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001391 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001392 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001393
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001395 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001396 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001399
1400 hdev->io_capability = cp->io_capability;
1401
1402 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001403 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001406 hci_dev_put(hdev);
1407
Szymon Janc4e51eae2011-02-25 19:05:48 +01001408 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001409}
1410
Johan Hedberge9a416b2011-02-19 12:05:56 -03001411static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1412{
1413 struct hci_dev *hdev = conn->hdev;
1414 struct list_head *p;
1415
1416 list_for_each(p, &cmd_list) {
1417 struct pending_cmd *cmd;
1418
1419 cmd = list_entry(p, struct pending_cmd, list);
1420
1421 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1422 continue;
1423
1424 if (cmd->index != hdev->id)
1425 continue;
1426
1427 if (cmd->user_data != conn)
1428 continue;
1429
1430 return cmd;
1431 }
1432
1433 return NULL;
1434}
1435
1436static void pairing_complete(struct pending_cmd *cmd, u8 status)
1437{
1438 struct mgmt_rp_pair_device rp;
1439 struct hci_conn *conn = cmd->user_data;
1440
Brian Gixa68668b2011-08-11 15:49:36 -07001441 BT_DBG(" %u", status);
1442
Johan Hedberge9a416b2011-02-19 12:05:56 -03001443 bacpy(&rp.bdaddr, &conn->dst);
1444 rp.status = status;
1445
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001447
1448 /* So we don't get further callbacks for this connection */
1449 conn->connect_cfm_cb = NULL;
1450 conn->security_cfm_cb = NULL;
1451 conn->disconn_cfm_cb = NULL;
1452
Johan Hedberga664b5b2011-02-19 12:06:02 -03001453 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001454}
1455
1456static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1457{
1458 struct pending_cmd *cmd;
1459
Brian Gixa68668b2011-08-11 15:49:36 -07001460 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001461
1462 cmd = find_pairing(conn);
1463 if (!cmd) {
1464 BT_DBG("Unable to find a pending command");
1465 return;
1466 }
1467
1468 pairing_complete(cmd, status);
1469}
1470
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001471static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001472{
1473 struct pending_cmd *cmd;
1474
1475 BT_DBG(" %u", status);
1476
1477 cmd = find_pairing(conn);
1478 if (!cmd) {
1479 BT_DBG("Unable to find a pending command");
1480 return;
1481 }
1482
1483 if (conn->type == LE_LINK)
1484 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1485 status ? 0 : 1);
1486 else
1487 pairing_complete(cmd, status);
1488}
1489
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001490static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001491{
1492 struct pending_cmd *cmd;
1493
1494 BT_DBG("conn: %p %u", conn, status);
1495
1496 cmd = find_pairing(conn);
1497 if (!cmd) {
1498 BT_DBG("Unable to find a pending command");
1499 return;
1500 }
Brian Gix114f3a62011-09-27 14:02:20 -07001501
1502 if (status)
1503 pairing_complete(cmd, status);
1504
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001505 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001506}
1507
1508static void discovery_terminated(struct pending_cmd *cmd, void *data)
1509{
1510 struct mgmt_mode ev = {0};
1511 struct disco_interleave *ilp = cmd->param;
1512
1513 BT_DBG("");
1514 del_timer_sync(&ilp->le_timer);
1515 del_timer_sync(&ilp->timer);
1516 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1517
1518 list_del(&cmd->list);
1519
1520 mgmt_pending_free(cmd);
1521}
1522
Szymon Janc4e51eae2011-02-25 19:05:48 +01001523static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001524{
1525 struct hci_dev *hdev;
1526 struct mgmt_cp_pair_device *cp;
1527 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001528 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001529 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001530 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001531 int err;
1532
1533 BT_DBG("");
1534
Brian Gix64bd5302011-09-08 11:35:48 -07001535 cp = (void *) data;
1536
1537 if (len != sizeof(*cp))
1538 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1539
Szymon Janc4e51eae2011-02-25 19:05:48 +01001540 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001541
Johan Hedberge9a416b2011-02-19 12:05:56 -03001542 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001543 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001546
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301547 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1548 io_cap = cp->io_cap;
1549 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001550 sec_level = BT_SECURITY_MEDIUM;
1551 auth_type = HCI_AT_DEDICATED_BONDING;
1552 } else {
1553 sec_level = BT_SECURITY_HIGH;
1554 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1555 }
1556
Brian Gixfdd38922011-09-28 16:23:48 -07001557 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1558 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001559 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1560 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001561 } else {
1562 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1563 if (io_cap == 0x04)
1564 io_cap = 0x01;
1565 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1566 auth_type);
1567 }
1568
Ville Tervo30e76272011-02-22 16:10:53 -03001569 if (IS_ERR(conn)) {
1570 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001571 goto unlock;
1572 }
1573
1574 if (conn->connect_cfm_cb) {
1575 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001576 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001577 goto unlock;
1578 }
1579
Szymon Janc4e51eae2011-02-25 19:05:48 +01001580 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001581 if (!cmd) {
1582 err = -ENOMEM;
1583 hci_conn_put(conn);
1584 goto unlock;
1585 }
1586
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001587 conn->connect_cfm_cb = pairing_connect_complete_cb;
1588 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001589 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001590 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001591 cmd->user_data = conn;
1592
1593 if (conn->state == BT_CONNECTED &&
1594 hci_conn_security(conn, sec_level, auth_type))
1595 pairing_complete(cmd, 0);
1596
1597 err = 0;
1598
1599unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001601 hci_dev_put(hdev);
1602
1603 return err;
1604}
1605
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001607 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001608{
1609 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001610 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001611 struct pending_cmd *cmd;
1612 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001613 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001614 int err;
1615
Brian Gixa68668b2011-08-11 15:49:36 -07001616 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001617
Brian Gixa68668b2011-08-11 15:49:36 -07001618 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001619 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001620 else
1621 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001622
Brian Gixa68668b2011-08-11 15:49:36 -07001623 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001624 return cmd_status(sk, index, mgmt_op, EINVAL);
1625
Szymon Janc4e51eae2011-02-25 19:05:48 +01001626 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001627 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001628 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001631
Johan Hedberga5c29682011-02-19 12:05:57 -03001632 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001633 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001634 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001635 }
1636
Brian Gixa68668b2011-08-11 15:49:36 -07001637 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1638 if (le_conn) {
1639 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1640 goto done;
1641 }
1642 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1643 "Reject" : "Accept");
1644
Szymon Janc4e51eae2011-02-25 19:05:48 +01001645 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001646 if (!cmd) {
1647 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001648 goto done;
1649 }
1650
1651 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1652 if (err < 0)
1653 mgmt_pending_remove(cmd);
1654
1655done:
1656 hci_dev_unlock(hdev);
1657 hci_dev_put(hdev);
1658
1659 return err;
1660}
1661
1662static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1663 u16 len)
1664{
1665 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1666 struct hci_cp_remote_name_req hci_cp;
1667 struct hci_dev *hdev;
1668 struct pending_cmd *cmd;
1669 int err;
1670
1671 BT_DBG("");
1672
1673 if (len != sizeof(*mgmt_cp))
1674 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1675
1676 hdev = hci_dev_get(index);
1677 if (!hdev)
1678 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1679
1680 hci_dev_lock(hdev);
1681
1682 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1683 if (!cmd) {
1684 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001685 goto failed;
1686 }
1687
Brian Gixa68668b2011-08-11 15:49:36 -07001688 memset(&hci_cp, 0, sizeof(hci_cp));
1689 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1690 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1691 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001692 if (err < 0)
1693 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001694
1695failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001697 hci_dev_put(hdev);
1698
1699 return err;
1700}
1701
Johan Hedbergb312b1612011-03-16 14:29:37 +02001702static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1703 u16 len)
1704{
1705 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1706 struct hci_cp_write_local_name hci_cp;
1707 struct hci_dev *hdev;
1708 struct pending_cmd *cmd;
1709 int err;
1710
1711 BT_DBG("");
1712
1713 if (len != sizeof(*mgmt_cp))
1714 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1715
1716 hdev = hci_dev_get(index);
1717 if (!hdev)
1718 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001721
1722 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1723 if (!cmd) {
1724 err = -ENOMEM;
1725 goto failed;
1726 }
1727
1728 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1729 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1730 &hci_cp);
1731 if (err < 0)
1732 mgmt_pending_remove(cmd);
1733
1734failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001736 hci_dev_put(hdev);
1737
1738 return err;
1739}
1740
Brian Gixa68668b2011-08-11 15:49:36 -07001741static void discovery_rsp(struct pending_cmd *cmd, void *data)
1742{
1743 struct mgmt_mode ev;
1744
1745 BT_DBG("");
1746 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1747 ev.val = 1;
1748 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1749 } else {
1750 ev.val = 0;
1751 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1752 NULL, 0);
1753 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1754 struct disco_interleave *ilp = cmd->param;
1755
1756 del_timer_sync(&ilp->le_timer);
1757 del_timer_sync(&ilp->timer);
1758 }
1759 }
1760
1761 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1762
1763 list_del(&cmd->list);
1764
1765 mgmt_pending_free(cmd);
1766}
1767
1768void mgmt_inquiry_started(u16 index)
1769{
1770 BT_DBG("");
1771 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1772 discovery_rsp, NULL);
1773}
1774
1775void mgmt_inquiry_complete_evt(u16 index, u8 status)
1776{
1777 struct hci_dev *hdev;
1778 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1779 struct pending_cmd *cmd;
1780 int err = -1;
1781
1782 BT_DBG("");
1783
1784 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001785
1786 if (hdev)
1787 hci_dev_lock(hdev);
1788
Brian Gixa68668b2011-08-11 15:49:36 -07001789 if (!hdev || !lmp_le_capable(hdev)) {
1790 struct mgmt_mode cp = {0};
1791
1792 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1793 discovery_terminated, NULL);
1794
1795 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001796
Brian Gix64bd5302011-09-08 11:35:48 -07001797 if (hdev)
1798 goto done;
1799 else
1800 return;
1801 }
Brian Gixa68668b2011-08-11 15:49:36 -07001802
1803 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1804 if (cmd && cmd->param) {
1805 struct disco_interleave *ilp = cmd->param;
1806
1807 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1808 sizeof(le_cp), &le_cp);
1809 if (err >= 0) {
1810 mod_timer(&ilp->le_timer, jiffies +
1811 msecs_to_jiffies(ilp->int_phase * 1000));
1812 ilp->mode = SCAN_LE;
1813 } else
1814 ilp->mode = SCAN_IDLE;
1815 }
1816
1817 if (err < 0)
1818 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1819 discovery_terminated, NULL);
1820
Brian Gix64bd5302011-09-08 11:35:48 -07001821done:
Brian Gixa68668b2011-08-11 15:49:36 -07001822 hci_dev_unlock(hdev);
1823 hci_dev_put(hdev);
1824}
1825
1826static void disco_to(unsigned long data)
1827{
1828 struct disco_interleave *ilp = (void *)data;
1829 struct hci_dev *hdev;
1830 struct pending_cmd *cmd;
1831
1832 BT_DBG("hci%d", ilp->index);
1833
1834 del_timer_sync(&ilp->le_timer);
1835 hdev = hci_dev_get(ilp->index);
1836
1837 if (hdev) {
1838 hci_dev_lock(hdev);
1839
1840 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1841
1842 if (ilp->mode != SCAN_IDLE) {
1843 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1844
1845 if (ilp->mode == SCAN_LE)
1846 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1847 sizeof(le_cp), &le_cp);
1848 else
1849 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1850 0, NULL);
1851
1852 ilp->mode = SCAN_IDLE;
1853 }
1854
1855 if (cmd) {
1856 struct mgmt_mode cp = {0};
1857
1858 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1859 sizeof(cp), NULL);
1860 mgmt_pending_remove(cmd);
1861 }
1862
1863 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001864 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001865 }
1866}
1867
1868static void disco_le_to(unsigned long data)
1869{
1870 struct disco_interleave *ilp = (void *)data;
1871 struct hci_dev *hdev;
1872 struct pending_cmd *cmd;
1873 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1874
1875 BT_DBG("hci%d", ilp->index);
1876
1877 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001878
1879 if (hdev) {
1880 hci_dev_lock(hdev);
1881
1882 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1883
1884 if (ilp->mode == SCAN_LE)
1885 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1886 sizeof(le_cp), &le_cp);
1887
1888 /* re-start BR scan */
1889 if (cmd) {
1890 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1891 ilp->int_phase *= 2;
1892 ilp->int_count = 0;
1893 cp.num_rsp = (u8) ilp->int_phase;
1894 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1895 ilp->mode = SCAN_BR;
1896 } else
1897 ilp->mode = SCAN_IDLE;
1898
1899 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001900 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001901 }
1902}
1903
1904static int start_discovery(struct sock *sk, u16 index)
1905{
1906 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1907 struct hci_dev *hdev;
1908 struct pending_cmd *cmd;
1909 int err;
1910
1911 BT_DBG("");
1912
1913 hdev = hci_dev_get(index);
1914 if (!hdev)
1915 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1916
1917 hci_dev_lock(hdev);
1918
1919 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1920 if (!cmd) {
1921 err = -ENOMEM;
1922 goto failed;
1923 }
1924
1925 /* If LE Capable, we will alternate between BR/EDR and LE */
1926 if (lmp_le_capable(hdev)) {
1927 struct hci_cp_le_set_scan_parameters le_cp;
1928
1929 /* Shorten BR scan params */
1930 cp.num_rsp = 1;
1931 cp.length /= 2;
1932
1933 /* Setup LE scan params */
1934 memset(&le_cp, 0, sizeof(le_cp));
1935 le_cp.type = 0x01; /* Active scanning */
1936 /* The recommended value for scan interval and window is
1937 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1938 le_cp.interval = cpu_to_le16(0x0012);
1939 le_cp.window = cpu_to_le16(0x0012);
1940 le_cp.own_bdaddr_type = 0; /* Public address */
1941 le_cp.filter = 0; /* Accept all adv packets */
1942
1943 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1944 sizeof(le_cp), &le_cp);
1945 }
1946
1947 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1948
1949 if (err < 0)
1950 mgmt_pending_remove(cmd);
1951 else if (lmp_le_capable(hdev)) {
1952 struct disco_interleave il, *ilp;
1953
1954 il.int_phase = 1;
1955 il.int_count = 0;
1956 il.index = index;
1957 il.mode = SCAN_BR;
1958 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
1959 sizeof(struct disco_interleave));
1960 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1961 if (cmd) {
1962 ilp = cmd->param;
1963 setup_timer(&ilp->le_timer, disco_le_to,
1964 (unsigned long) ilp);
1965 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
1966 mod_timer(&ilp->timer,
1967 jiffies + msecs_to_jiffies(20000));
1968 }
1969 }
1970
1971failed:
1972 hci_dev_unlock(hdev);
1973 hci_dev_put(hdev);
1974
1975 return err;
1976}
1977
1978static int stop_discovery(struct sock *sk, u16 index)
1979{
1980 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1981 struct mgmt_mode mode_cp = {0};
1982 struct disco_interleave *ilp = NULL;
1983 struct hci_dev *hdev;
1984 struct pending_cmd *cmd = NULL;
1985 int err = -EPERM;
1986
1987 BT_DBG("");
1988
1989 hdev = hci_dev_get(index);
1990 if (!hdev)
1991 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1992
1993 hci_dev_lock(hdev);
1994
1995 if (lmp_le_capable(hdev)) {
1996 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1997 if (!cmd) {
1998 err = -ENOMEM;
1999 goto failed;
2000 }
2001
2002 ilp = cmd->param;
2003 }
2004
2005 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2006 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2007 sizeof(le_cp), &le_cp);
2008
2009 if (err < 0) {
2010 if (!ilp || (ilp->mode == SCAN_BR))
2011 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2012 0, NULL);
2013 }
2014
2015 if (ilp) {
2016 ilp->mode = SCAN_IDLE;
2017 del_timer_sync(&ilp->le_timer);
2018 del_timer_sync(&ilp->timer);
2019 }
2020
2021 if (err < 0 && cmd)
2022 mgmt_pending_remove(cmd);
2023
2024 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2025
2026failed:
2027 hci_dev_unlock(hdev);
2028 hci_dev_put(hdev);
2029
2030 if (err < 0)
2031 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2032 else
2033 return err;
2034}
2035
Szymon Jancc35938b2011-03-22 13:12:21 +01002036static int read_local_oob_data(struct sock *sk, u16 index)
2037{
2038 struct hci_dev *hdev;
2039 struct pending_cmd *cmd;
2040 int err;
2041
2042 BT_DBG("hci%u", index);
2043
2044 hdev = hci_dev_get(index);
2045 if (!hdev)
2046 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2047 ENODEV);
2048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002049 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002050
2051 if (!test_bit(HCI_UP, &hdev->flags)) {
2052 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2053 ENETDOWN);
2054 goto unlock;
2055 }
2056
2057 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2058 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2059 EOPNOTSUPP);
2060 goto unlock;
2061 }
2062
2063 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2064 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2065 goto unlock;
2066 }
2067
2068 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2069 if (!cmd) {
2070 err = -ENOMEM;
2071 goto unlock;
2072 }
2073
2074 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2075 if (err < 0)
2076 mgmt_pending_remove(cmd);
2077
2078unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002080 hci_dev_put(hdev);
2081
2082 return err;
2083}
2084
Szymon Janc2763eda2011-03-22 13:12:22 +01002085static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2086 u16 len)
2087{
2088 struct hci_dev *hdev;
2089 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2090 int err;
2091
2092 BT_DBG("hci%u ", index);
2093
2094 if (len != sizeof(*cp))
2095 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2096 EINVAL);
2097
2098 hdev = hci_dev_get(index);
2099 if (!hdev)
2100 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2101 ENODEV);
2102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002104
2105 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2106 cp->randomizer);
2107 if (err < 0)
2108 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2109 else
2110 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2111 0);
2112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002114 hci_dev_put(hdev);
2115
2116 return err;
2117}
2118
2119static int remove_remote_oob_data(struct sock *sk, u16 index,
2120 unsigned char *data, u16 len)
2121{
2122 struct hci_dev *hdev;
2123 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2124 int err;
2125
2126 BT_DBG("hci%u ", index);
2127
2128 if (len != sizeof(*cp))
2129 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2130 EINVAL);
2131
2132 hdev = hci_dev_get(index);
2133 if (!hdev)
2134 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2135 ENODEV);
2136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002138
2139 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2140 if (err < 0)
2141 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2142 -err);
2143 else
2144 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2145 NULL, 0);
2146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002148 hci_dev_put(hdev);
2149
2150 return err;
2151}
2152
Johan Hedberg03811012010-12-08 00:21:06 +02002153int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2154{
2155 unsigned char *buf;
2156 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002157 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002158 int err;
2159
2160 BT_DBG("got %zu bytes", msglen);
2161
2162 if (msglen < sizeof(*hdr))
2163 return -EINVAL;
2164
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002165 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002166 if (!buf)
2167 return -ENOMEM;
2168
2169 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2170 err = -EFAULT;
2171 goto done;
2172 }
2173
2174 hdr = (struct mgmt_hdr *) buf;
2175 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002176 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002177 len = get_unaligned_le16(&hdr->len);
2178
2179 if (len != msglen - sizeof(*hdr)) {
2180 err = -EINVAL;
2181 goto done;
2182 }
2183
Brian Gixa68668b2011-08-11 15:49:36 -07002184 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002185 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002186 case MGMT_OP_READ_VERSION:
2187 err = read_version(sk);
2188 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002189 case MGMT_OP_READ_INDEX_LIST:
2190 err = read_index_list(sk);
2191 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002192 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002193 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002194 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002195 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002196 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002197 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002198 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002199 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002200 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002201 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2202 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2203 len);
2204 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002205 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002206 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002207 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002208 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002209 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002210 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002211 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002212 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002213 break;
2214 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002215 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002216 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002217 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002218 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002219 break;
2220 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002221 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002222 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002223 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002224 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002225 break;
2226 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002227 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002228 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002229 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002230 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002231 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002232 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002233 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002234 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002235 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002236 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002237 break;
2238 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002239 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002240 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002242 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002243 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002245 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002246 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002247 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002248 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002249 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002250 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2251 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002252 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002253 case MGMT_OP_SET_LOCAL_NAME:
2254 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2255 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002256 case MGMT_OP_START_DISCOVERY:
2257 err = start_discovery(sk, index);
2258 break;
2259 case MGMT_OP_STOP_DISCOVERY:
2260 err = stop_discovery(sk, index);
2261 break;
2262 case MGMT_OP_RESOLVE_NAME:
2263 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2264 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002265 case MGMT_OP_READ_LOCAL_OOB_DATA:
2266 err = read_local_oob_data(sk, index);
2267 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002268 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2269 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2270 break;
2271 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2272 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2273 len);
2274 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275
Johan Hedberg03811012010-12-08 00:21:06 +02002276 default:
2277 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002278 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002279 break;
2280 }
2281
Johan Hedberge41d8b42010-12-13 21:07:03 +02002282 if (err < 0)
2283 goto done;
2284
Johan Hedberg03811012010-12-08 00:21:06 +02002285 err = msglen;
2286
2287done:
2288 kfree(buf);
2289 return err;
2290}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002291
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002292int mgmt_index_added(u16 index)
2293{
Brian Gixa68668b2011-08-11 15:49:36 -07002294 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002295 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002296}
2297
2298int mgmt_index_removed(u16 index)
2299{
Brian Gixa68668b2011-08-11 15:49:36 -07002300 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002301 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002302}
2303
Johan Hedberg73f22f62010-12-29 16:00:25 +02002304struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002305 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002306 struct sock *sk;
2307};
2308
Johan Hedberg72a734e2010-12-30 00:38:22 +02002309static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002310{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002311 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002312 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002313
Johan Hedberg72a734e2010-12-30 00:38:22 +02002314 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002315 return;
2316
Johan Hedberg053f0212011-01-26 13:07:10 +02002317 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002318
2319 list_del(&cmd->list);
2320
2321 if (match->sk == NULL) {
2322 match->sk = cmd->sk;
2323 sock_hold(match->sk);
2324 }
2325
2326 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002327}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002328
2329int mgmt_powered(u16 index, u8 powered)
2330{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002331 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002332 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002333 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002334
Brian Gixa68668b2011-08-11 15:49:36 -07002335 BT_DBG("hci%u %d", index, powered);
2336
Johan Hedberg72a734e2010-12-30 00:38:22 +02002337 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002338
Johan Hedberg72a734e2010-12-30 00:38:22 +02002339 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002340
Szymon Janc4e51eae2011-02-25 19:05:48 +01002341 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002342
2343 if (match.sk)
2344 sock_put(match.sk);
2345
2346 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002347}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002348
Johan Hedberg73f22f62010-12-29 16:00:25 +02002349int mgmt_discoverable(u16 index, u8 discoverable)
2350{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002351 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002352 struct cmd_lookup match = { discoverable, NULL };
2353 int ret;
2354
Szymon Jancb8534e02011-03-01 16:55:34 +01002355 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002356
Johan Hedberg72a734e2010-12-30 00:38:22 +02002357 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002358
Szymon Janc4e51eae2011-02-25 19:05:48 +01002359 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2360 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002361
2362 if (match.sk)
2363 sock_put(match.sk);
2364
2365 return ret;
2366}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002367
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002368int mgmt_connectable(u16 index, u8 connectable)
2369{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002370 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002371 struct cmd_lookup match = { connectable, NULL };
2372 int ret;
2373
Johan Hedberg72a734e2010-12-30 00:38:22 +02002374 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002375
Johan Hedberg72a734e2010-12-30 00:38:22 +02002376 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002377
Szymon Janc4e51eae2011-02-25 19:05:48 +01002378 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002379
2380 if (match.sk)
2381 sock_put(match.sk);
2382
2383 return ret;
2384}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002385
Brian Gixa68668b2011-08-11 15:49:36 -07002386int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002387{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002388 struct mgmt_ev_new_key *ev;
2389 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002390
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002391 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2392 ev = kzalloc(total, GFP_ATOMIC);
2393 if (!ev)
2394 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002395
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002396 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002397 ev->key.addr_type = key->addr_type;
2398 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002399 memcpy(ev->key.val, key->val, 16);
2400 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002401 ev->key.auth = key->auth;
2402 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002403 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002404
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002405 memcpy(ev->key.data, key->data, key->dlen);
2406
2407 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2408
2409 kfree(ev);
2410
2411 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002412}
Johan Hedbergf7520542011-01-20 12:34:39 +02002413
Brian Gix2e2f50d2011-09-13 12:36:04 -07002414int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002415{
2416 struct mgmt_ev_connected ev;
2417
Johan Hedbergf7520542011-01-20 12:34:39 +02002418 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002419 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002420
Szymon Janc4e51eae2011-02-25 19:05:48 +01002421 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002422}
2423
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2425{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002426 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002427 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002428 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429
Johan Hedberga38528f2011-01-22 06:46:43 +02002430 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002431
Szymon Janc4e51eae2011-02-25 19:05:48 +01002432 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002433
2434 *sk = cmd->sk;
2435 sock_hold(*sk);
2436
Johan Hedberga664b5b2011-02-19 12:06:02 -03002437 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438}
2439
Johan Hedbergf7520542011-01-20 12:34:39 +02002440int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2441{
2442 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002443 struct sock *sk = NULL;
2444 int err;
2445
2446 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002447
Johan Hedbergf7520542011-01-20 12:34:39 +02002448 bacpy(&ev.bdaddr, bdaddr);
2449
Szymon Janc4e51eae2011-02-25 19:05:48 +01002450 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002451
2452 if (sk)
2453 sock_put(sk);
2454
2455 return err;
2456}
2457
2458int mgmt_disconnect_failed(u16 index)
2459{
2460 struct pending_cmd *cmd;
2461 int err;
2462
2463 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2464 if (!cmd)
2465 return -ENOENT;
2466
Szymon Janc4e51eae2011-02-25 19:05:48 +01002467 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002468
Johan Hedberga664b5b2011-02-19 12:06:02 -03002469 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002470
2471 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002472}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002473
2474int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2475{
2476 struct mgmt_ev_connect_failed ev;
2477
Johan Hedberg17d5c042011-01-22 06:09:08 +02002478 bacpy(&ev.bdaddr, bdaddr);
2479 ev.status = status;
2480
Szymon Janc4e51eae2011-02-25 19:05:48 +01002481 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002482}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485{
2486 struct mgmt_ev_pin_code_request ev;
2487
Brian Gixa68668b2011-08-11 15:49:36 -07002488 BT_DBG("hci%u", index);
2489
Johan Hedberg980e1a52011-01-22 06:10:07 +02002490 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002491 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002492
Szymon Janc4e51eae2011-02-25 19:05:48 +01002493 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2494 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002495}
2496
2497int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2498{
2499 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002500 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002501 int err;
2502
2503 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2504 if (!cmd)
2505 return -ENOENT;
2506
Johan Hedbergac56fb12011-02-19 12:05:59 -03002507 bacpy(&rp.bdaddr, bdaddr);
2508 rp.status = status;
2509
Szymon Janc4e51eae2011-02-25 19:05:48 +01002510 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2511 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002512
Johan Hedberga664b5b2011-02-19 12:06:02 -03002513 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002514
2515 return err;
2516}
2517
2518int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2519{
2520 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002521 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002522 int err;
2523
2524 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2525 if (!cmd)
2526 return -ENOENT;
2527
Johan Hedbergac56fb12011-02-19 12:05:59 -03002528 bacpy(&rp.bdaddr, bdaddr);
2529 rp.status = status;
2530
Szymon Janc4e51eae2011-02-25 19:05:48 +01002531 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2532 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533
Johan Hedberga664b5b2011-02-19 12:06:02 -03002534 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002535
2536 return err;
2537}
Johan Hedberga5c29682011-02-19 12:05:57 -03002538
Brian Gixa68668b2011-08-11 15:49:36 -07002539int mgmt_user_confirm_request(u16 index, u8 event,
2540 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002541{
2542 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002543 struct hci_conn *conn = NULL;
2544 struct hci_dev *hdev;
2545 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2546
2547 BT_DBG("hci%u", index);
2548
2549 hdev = hci_dev_get(index);
2550
Brian Gix64bd5302011-09-08 11:35:48 -07002551 if (!hdev)
2552 return -ENODEV;
2553
Brian Gix64bd5302011-09-08 11:35:48 -07002554 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002555
2556 ev.auto_confirm = 0;
2557
2558 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2559 goto no_auto_confirm;
2560
2561 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2562 rem_cap = conn->remote_cap;
2563 loc_mitm = conn->auth_type & 0x01;
2564 rem_mitm = conn->remote_auth & 0x01;
2565
2566 if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
2567 goto no_auto_confirm;
2568
2569
2570 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2571 ev.auto_confirm = 1;
2572
2573no_auto_confirm:
2574 bacpy(&ev.bdaddr, bdaddr);
2575 ev.event = event;
2576 put_unaligned_le32(value, &ev.value);
2577
Brian Gix64bd5302011-09-08 11:35:48 -07002578 hci_dev_put(hdev);
2579
Brian Gixa68668b2011-08-11 15:49:36 -07002580 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2581 NULL);
2582}
2583
2584int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2585{
2586 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002587
2588 BT_DBG("hci%u", index);
2589
Johan Hedberga5c29682011-02-19 12:05:57 -03002590 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002591
Brian Gixa68668b2011-08-11 15:49:36 -07002592 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002593 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002594}
2595
2596static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2597 u8 opcode)
2598{
2599 struct pending_cmd *cmd;
2600 struct mgmt_rp_user_confirm_reply rp;
2601 int err;
2602
2603 cmd = mgmt_pending_find(opcode, index);
2604 if (!cmd)
2605 return -ENOENT;
2606
Johan Hedberga5c29682011-02-19 12:05:57 -03002607 bacpy(&rp.bdaddr, bdaddr);
2608 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002609 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002610
Johan Hedberga664b5b2011-02-19 12:06:02 -03002611 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002612
2613 return err;
2614}
2615
2616int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2617{
2618 return confirm_reply_complete(index, bdaddr, status,
2619 MGMT_OP_USER_CONFIRM_REPLY);
2620}
2621
Szymon Jancb8534e02011-03-01 16:55:34 +01002622int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002623{
2624 return confirm_reply_complete(index, bdaddr, status,
2625 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2626}
Johan Hedberg2a611692011-02-19 12:06:00 -03002627
2628int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2629{
2630 struct mgmt_ev_auth_failed ev;
2631
Johan Hedberg2a611692011-02-19 12:06:00 -03002632 bacpy(&ev.bdaddr, bdaddr);
2633 ev.status = status;
2634
Szymon Janc4e51eae2011-02-25 19:05:48 +01002635 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002636}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637
2638int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2639{
2640 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002641 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002642 struct mgmt_cp_set_local_name ev;
2643 int err;
2644
2645 memset(&ev, 0, sizeof(ev));
2646 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2647
2648 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2649 if (!cmd)
2650 goto send_event;
2651
2652 if (status) {
2653 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2654 goto failed;
2655 }
2656
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002657 hdev = hci_dev_get(index);
2658 if (hdev) {
2659 hci_dev_lock_bh(hdev);
2660 update_eir(hdev);
2661 hci_dev_unlock_bh(hdev);
2662 hci_dev_put(hdev);
2663 }
2664
Johan Hedbergb312b1612011-03-16 14:29:37 +02002665 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2666 sizeof(ev));
2667 if (err < 0)
2668 goto failed;
2669
2670send_event:
2671 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2672 cmd ? cmd->sk : NULL);
2673
2674failed:
2675 if (cmd)
2676 mgmt_pending_remove(cmd);
2677 return err;
2678}
Szymon Jancc35938b2011-03-22 13:12:21 +01002679
2680int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2681 u8 status)
2682{
2683 struct pending_cmd *cmd;
2684 int err;
2685
2686 BT_DBG("hci%u status %u", index, status);
2687
2688 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2689 if (!cmd)
2690 return -ENOENT;
2691
2692 if (status) {
2693 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2694 EIO);
2695 } else {
2696 struct mgmt_rp_read_local_oob_data rp;
2697
2698 memcpy(rp.hash, hash, sizeof(rp.hash));
2699 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2700
2701 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2702 &rp, sizeof(rp));
2703 }
2704
2705 mgmt_pending_remove(cmd);
2706
2707 return err;
2708}
Johan Hedberge17acd42011-03-30 23:57:16 +03002709
Brian Gixa68668b2011-08-11 15:49:36 -07002710int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2711 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002712{
2713 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002714 struct pending_cmd *cmd;
2715 int err;
2716
2717 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002718
2719 memset(&ev, 0, sizeof(ev));
2720
2721 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002722 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002723 ev.type = type;
2724 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002725
Brian Gixa68668b2011-08-11 15:49:36 -07002726 if (dev_class)
2727 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002728
Brian Gixa68668b2011-08-11 15:49:36 -07002729 if (eir && eir_len)
2730 memcpy(ev.eir, eir, eir_len);
2731
2732 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2733
2734 if (err < 0)
2735 return err;
2736
2737 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2738 if (cmd) {
2739 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002740 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002741
2742 ilp->int_count++;
2743 if (hdev && ilp->int_count >= ilp->int_phase) {
2744 /* Inquiry scan for General Discovery LAP */
2745 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2746 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002747
Brian Gixa68668b2011-08-11 15:49:36 -07002748 ilp->int_phase *= 2;
2749 ilp->int_count = 0;
2750 if (ilp->mode == SCAN_LE) {
2751 /* cancel LE scan */
2752 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2753 sizeof(le_cp), &le_cp);
2754 /* start BR scan */
2755 cp.num_rsp = (u8) ilp->int_phase;
2756 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2757 sizeof(cp), &cp);
2758 ilp->mode = SCAN_BR;
2759 del_timer_sync(&ilp->le_timer);
2760 }
2761 }
Brian Gix64bd5302011-09-08 11:35:48 -07002762
2763 if (hdev)
2764 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002765 }
2766
2767 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002768}
Johan Hedberga88a9652011-03-30 13:18:12 +03002769
Brian Gixa68668b2011-08-11 15:49:36 -07002770
2771int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002772{
2773 struct mgmt_ev_remote_name ev;
2774
2775 memset(&ev, 0, sizeof(ev));
2776
2777 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002778 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002779 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2780
2781 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2782}