blob: 0e7ff51312b007898d8f860988a59a3caa9b6a00 [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
Brian Gix7f7e16c2011-11-01 16:27:25 -07001702static int set_connection_params(struct sock *sk, u16 index,
1703 unsigned char *data, u16 len)
1704{
1705 struct mgmt_cp_set_connection_params *cp = (void *) data;
1706 struct hci_dev *hdev;
1707 struct hci_conn *conn;
1708 int err;
1709
1710 BT_DBG("");
1711
1712 if (len != sizeof(*cp))
1713 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1714 EINVAL);
1715
1716 hdev = hci_dev_get(index);
1717 if (!hdev)
1718 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1719 ENODEV);
1720
1721 hci_dev_lock(hdev);
1722
1723 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1724 if (!conn) {
1725 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1726 ENOTCONN);
1727 goto failed;
1728 }
1729
1730 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1731 le16_to_cpu(cp->interval_max),
1732 le16_to_cpu(cp->slave_latency),
1733 le16_to_cpu(cp->timeout_multiplier));
1734
1735 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1736
1737failed:
1738 hci_dev_unlock(hdev);
1739 hci_dev_put(hdev);
1740
1741 return err;
1742}
1743
Johan Hedbergb312b1612011-03-16 14:29:37 +02001744static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1745 u16 len)
1746{
1747 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1748 struct hci_cp_write_local_name hci_cp;
1749 struct hci_dev *hdev;
1750 struct pending_cmd *cmd;
1751 int err;
1752
1753 BT_DBG("");
1754
1755 if (len != sizeof(*mgmt_cp))
1756 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1757
1758 hdev = hci_dev_get(index);
1759 if (!hdev)
1760 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001763
1764 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1765 if (!cmd) {
1766 err = -ENOMEM;
1767 goto failed;
1768 }
1769
1770 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1771 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1772 &hci_cp);
1773 if (err < 0)
1774 mgmt_pending_remove(cmd);
1775
1776failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001778 hci_dev_put(hdev);
1779
1780 return err;
1781}
1782
Brian Gixa68668b2011-08-11 15:49:36 -07001783static void discovery_rsp(struct pending_cmd *cmd, void *data)
1784{
1785 struct mgmt_mode ev;
1786
1787 BT_DBG("");
1788 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1789 ev.val = 1;
1790 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1791 } else {
1792 ev.val = 0;
1793 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1794 NULL, 0);
1795 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1796 struct disco_interleave *ilp = cmd->param;
1797
1798 del_timer_sync(&ilp->le_timer);
1799 del_timer_sync(&ilp->timer);
1800 }
1801 }
1802
1803 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1804
1805 list_del(&cmd->list);
1806
1807 mgmt_pending_free(cmd);
1808}
1809
1810void mgmt_inquiry_started(u16 index)
1811{
1812 BT_DBG("");
1813 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1814 discovery_rsp, NULL);
1815}
1816
1817void mgmt_inquiry_complete_evt(u16 index, u8 status)
1818{
1819 struct hci_dev *hdev;
1820 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1821 struct pending_cmd *cmd;
1822 int err = -1;
1823
1824 BT_DBG("");
1825
1826 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001827
1828 if (hdev)
1829 hci_dev_lock(hdev);
1830
Brian Gixa68668b2011-08-11 15:49:36 -07001831 if (!hdev || !lmp_le_capable(hdev)) {
1832 struct mgmt_mode cp = {0};
1833
1834 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1835 discovery_terminated, NULL);
1836
1837 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001838
Brian Gix64bd5302011-09-08 11:35:48 -07001839 if (hdev)
1840 goto done;
1841 else
1842 return;
1843 }
Brian Gixa68668b2011-08-11 15:49:36 -07001844
1845 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1846 if (cmd && cmd->param) {
1847 struct disco_interleave *ilp = cmd->param;
1848
1849 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1850 sizeof(le_cp), &le_cp);
1851 if (err >= 0) {
1852 mod_timer(&ilp->le_timer, jiffies +
1853 msecs_to_jiffies(ilp->int_phase * 1000));
1854 ilp->mode = SCAN_LE;
1855 } else
1856 ilp->mode = SCAN_IDLE;
1857 }
1858
1859 if (err < 0)
1860 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1861 discovery_terminated, NULL);
1862
Brian Gix64bd5302011-09-08 11:35:48 -07001863done:
Brian Gixa68668b2011-08-11 15:49:36 -07001864 hci_dev_unlock(hdev);
1865 hci_dev_put(hdev);
1866}
1867
1868static void disco_to(unsigned long data)
1869{
1870 struct disco_interleave *ilp = (void *)data;
1871 struct hci_dev *hdev;
1872 struct pending_cmd *cmd;
1873
1874 BT_DBG("hci%d", ilp->index);
1875
1876 del_timer_sync(&ilp->le_timer);
1877 hdev = hci_dev_get(ilp->index);
1878
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_IDLE) {
1885 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1886
1887 if (ilp->mode == SCAN_LE)
1888 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1889 sizeof(le_cp), &le_cp);
1890 else
1891 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1892 0, NULL);
1893
1894 ilp->mode = SCAN_IDLE;
1895 }
1896
1897 if (cmd) {
1898 struct mgmt_mode cp = {0};
1899
1900 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1901 sizeof(cp), NULL);
1902 mgmt_pending_remove(cmd);
1903 }
1904
1905 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001906 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001907 }
1908}
1909
1910static void disco_le_to(unsigned long data)
1911{
1912 struct disco_interleave *ilp = (void *)data;
1913 struct hci_dev *hdev;
1914 struct pending_cmd *cmd;
1915 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1916
1917 BT_DBG("hci%d", ilp->index);
1918
1919 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001920
1921 if (hdev) {
1922 hci_dev_lock(hdev);
1923
1924 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1925
1926 if (ilp->mode == SCAN_LE)
1927 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1928 sizeof(le_cp), &le_cp);
1929
1930 /* re-start BR scan */
1931 if (cmd) {
1932 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1933 ilp->int_phase *= 2;
1934 ilp->int_count = 0;
1935 cp.num_rsp = (u8) ilp->int_phase;
1936 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1937 ilp->mode = SCAN_BR;
1938 } else
1939 ilp->mode = SCAN_IDLE;
1940
1941 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001942 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001943 }
1944}
1945
1946static int start_discovery(struct sock *sk, u16 index)
1947{
1948 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
1949 struct hci_dev *hdev;
1950 struct pending_cmd *cmd;
1951 int err;
1952
1953 BT_DBG("");
1954
1955 hdev = hci_dev_get(index);
1956 if (!hdev)
1957 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1958
1959 hci_dev_lock(hdev);
1960
1961 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1962 if (!cmd) {
1963 err = -ENOMEM;
1964 goto failed;
1965 }
1966
1967 /* If LE Capable, we will alternate between BR/EDR and LE */
1968 if (lmp_le_capable(hdev)) {
1969 struct hci_cp_le_set_scan_parameters le_cp;
1970
1971 /* Shorten BR scan params */
1972 cp.num_rsp = 1;
1973 cp.length /= 2;
1974
1975 /* Setup LE scan params */
1976 memset(&le_cp, 0, sizeof(le_cp));
1977 le_cp.type = 0x01; /* Active scanning */
1978 /* The recommended value for scan interval and window is
1979 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
1980 le_cp.interval = cpu_to_le16(0x0012);
1981 le_cp.window = cpu_to_le16(0x0012);
1982 le_cp.own_bdaddr_type = 0; /* Public address */
1983 le_cp.filter = 0; /* Accept all adv packets */
1984
1985 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
1986 sizeof(le_cp), &le_cp);
1987 }
1988
1989 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1990
1991 if (err < 0)
1992 mgmt_pending_remove(cmd);
1993 else if (lmp_le_capable(hdev)) {
1994 struct disco_interleave il, *ilp;
1995
1996 il.int_phase = 1;
1997 il.int_count = 0;
1998 il.index = index;
1999 il.mode = SCAN_BR;
2000 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
2001 sizeof(struct disco_interleave));
2002 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2003 if (cmd) {
2004 ilp = cmd->param;
2005 setup_timer(&ilp->le_timer, disco_le_to,
2006 (unsigned long) ilp);
2007 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
2008 mod_timer(&ilp->timer,
2009 jiffies + msecs_to_jiffies(20000));
2010 }
2011 }
2012
2013failed:
2014 hci_dev_unlock(hdev);
2015 hci_dev_put(hdev);
2016
2017 return err;
2018}
2019
2020static int stop_discovery(struct sock *sk, u16 index)
2021{
2022 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2023 struct mgmt_mode mode_cp = {0};
2024 struct disco_interleave *ilp = NULL;
2025 struct hci_dev *hdev;
2026 struct pending_cmd *cmd = NULL;
2027 int err = -EPERM;
2028
2029 BT_DBG("");
2030
2031 hdev = hci_dev_get(index);
2032 if (!hdev)
2033 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2034
2035 hci_dev_lock(hdev);
2036
2037 if (lmp_le_capable(hdev)) {
2038 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2039 if (!cmd) {
2040 err = -ENOMEM;
2041 goto failed;
2042 }
2043
2044 ilp = cmd->param;
2045 }
2046
2047 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2048 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2049 sizeof(le_cp), &le_cp);
2050
2051 if (err < 0) {
2052 if (!ilp || (ilp->mode == SCAN_BR))
2053 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2054 0, NULL);
2055 }
2056
2057 if (ilp) {
2058 ilp->mode = SCAN_IDLE;
2059 del_timer_sync(&ilp->le_timer);
2060 del_timer_sync(&ilp->timer);
2061 }
2062
2063 if (err < 0 && cmd)
2064 mgmt_pending_remove(cmd);
2065
2066 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2067
2068failed:
2069 hci_dev_unlock(hdev);
2070 hci_dev_put(hdev);
2071
2072 if (err < 0)
2073 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2074 else
2075 return err;
2076}
2077
Szymon Jancc35938b2011-03-22 13:12:21 +01002078static int read_local_oob_data(struct sock *sk, u16 index)
2079{
2080 struct hci_dev *hdev;
2081 struct pending_cmd *cmd;
2082 int err;
2083
2084 BT_DBG("hci%u", index);
2085
2086 hdev = hci_dev_get(index);
2087 if (!hdev)
2088 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2089 ENODEV);
2090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002092
2093 if (!test_bit(HCI_UP, &hdev->flags)) {
2094 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2095 ENETDOWN);
2096 goto unlock;
2097 }
2098
2099 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2100 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2101 EOPNOTSUPP);
2102 goto unlock;
2103 }
2104
2105 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2106 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2107 goto unlock;
2108 }
2109
2110 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2111 if (!cmd) {
2112 err = -ENOMEM;
2113 goto unlock;
2114 }
2115
2116 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2117 if (err < 0)
2118 mgmt_pending_remove(cmd);
2119
2120unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002122 hci_dev_put(hdev);
2123
2124 return err;
2125}
2126
Szymon Janc2763eda2011-03-22 13:12:22 +01002127static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2128 u16 len)
2129{
2130 struct hci_dev *hdev;
2131 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2132 int err;
2133
2134 BT_DBG("hci%u ", index);
2135
2136 if (len != sizeof(*cp))
2137 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2138 EINVAL);
2139
2140 hdev = hci_dev_get(index);
2141 if (!hdev)
2142 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2143 ENODEV);
2144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002146
2147 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2148 cp->randomizer);
2149 if (err < 0)
2150 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2151 else
2152 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2153 0);
2154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002156 hci_dev_put(hdev);
2157
2158 return err;
2159}
2160
2161static int remove_remote_oob_data(struct sock *sk, u16 index,
2162 unsigned char *data, u16 len)
2163{
2164 struct hci_dev *hdev;
2165 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2166 int err;
2167
2168 BT_DBG("hci%u ", index);
2169
2170 if (len != sizeof(*cp))
2171 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2172 EINVAL);
2173
2174 hdev = hci_dev_get(index);
2175 if (!hdev)
2176 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2177 ENODEV);
2178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002180
2181 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2182 if (err < 0)
2183 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2184 -err);
2185 else
2186 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2187 NULL, 0);
2188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002190 hci_dev_put(hdev);
2191
2192 return err;
2193}
2194
Johan Hedberg03811012010-12-08 00:21:06 +02002195int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2196{
2197 unsigned char *buf;
2198 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002199 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002200 int err;
2201
2202 BT_DBG("got %zu bytes", msglen);
2203
2204 if (msglen < sizeof(*hdr))
2205 return -EINVAL;
2206
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002207 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002208 if (!buf)
2209 return -ENOMEM;
2210
2211 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2212 err = -EFAULT;
2213 goto done;
2214 }
2215
2216 hdr = (struct mgmt_hdr *) buf;
2217 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002218 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002219 len = get_unaligned_le16(&hdr->len);
2220
2221 if (len != msglen - sizeof(*hdr)) {
2222 err = -EINVAL;
2223 goto done;
2224 }
2225
Brian Gixa68668b2011-08-11 15:49:36 -07002226 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002227 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002228 case MGMT_OP_READ_VERSION:
2229 err = read_version(sk);
2230 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002231 case MGMT_OP_READ_INDEX_LIST:
2232 err = read_index_list(sk);
2233 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002234 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002235 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002236 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002237 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002238 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002239 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002240 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002241 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002242 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002243 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2244 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2245 len);
2246 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002247 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002248 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002249 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002250 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002251 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002252 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002253 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002254 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002255 break;
2256 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002257 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002258 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002259 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002260 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002261 break;
2262 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002263 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002264 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002265 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002266 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002267 break;
2268 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002269 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002270 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002271 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002272 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002273 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002274 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002275 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002276 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002277 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002278 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002279 break;
2280 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002281 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002282 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002283 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002284 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002285 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002286 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002287 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002288 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002289 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002290 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002291 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002292 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2293 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002294 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002295 case MGMT_OP_SET_LOCAL_NAME:
2296 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2297 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002298 case MGMT_OP_START_DISCOVERY:
2299 err = start_discovery(sk, index);
2300 break;
2301 case MGMT_OP_STOP_DISCOVERY:
2302 err = stop_discovery(sk, index);
2303 break;
2304 case MGMT_OP_RESOLVE_NAME:
2305 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2306 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002307 case MGMT_OP_SET_CONNECTION_PARAMS:
2308 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2309 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002310 case MGMT_OP_READ_LOCAL_OOB_DATA:
2311 err = read_local_oob_data(sk, index);
2312 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002313 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2314 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2315 break;
2316 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2317 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2318 len);
2319 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320
Johan Hedberg03811012010-12-08 00:21:06 +02002321 default:
2322 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002323 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002324 break;
2325 }
2326
Johan Hedberge41d8b42010-12-13 21:07:03 +02002327 if (err < 0)
2328 goto done;
2329
Johan Hedberg03811012010-12-08 00:21:06 +02002330 err = msglen;
2331
2332done:
2333 kfree(buf);
2334 return err;
2335}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002336
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002337int mgmt_index_added(u16 index)
2338{
Brian Gixa68668b2011-08-11 15:49:36 -07002339 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002340 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002341}
2342
2343int mgmt_index_removed(u16 index)
2344{
Brian Gixa68668b2011-08-11 15:49:36 -07002345 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002346 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002347}
2348
Johan Hedberg73f22f62010-12-29 16:00:25 +02002349struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002350 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002351 struct sock *sk;
2352};
2353
Johan Hedberg72a734e2010-12-30 00:38:22 +02002354static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002355{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002356 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002357 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002358
Johan Hedberg72a734e2010-12-30 00:38:22 +02002359 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002360 return;
2361
Johan Hedberg053f0212011-01-26 13:07:10 +02002362 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002363
2364 list_del(&cmd->list);
2365
2366 if (match->sk == NULL) {
2367 match->sk = cmd->sk;
2368 sock_hold(match->sk);
2369 }
2370
2371 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002372}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002373
2374int mgmt_powered(u16 index, u8 powered)
2375{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002376 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002377 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002378 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002379
Brian Gixa68668b2011-08-11 15:49:36 -07002380 BT_DBG("hci%u %d", index, powered);
2381
Johan Hedberg72a734e2010-12-30 00:38:22 +02002382 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002383
Johan Hedberg72a734e2010-12-30 00:38:22 +02002384 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002385
Szymon Janc4e51eae2011-02-25 19:05:48 +01002386 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002387
2388 if (match.sk)
2389 sock_put(match.sk);
2390
2391 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002392}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002393
Johan Hedberg73f22f62010-12-29 16:00:25 +02002394int mgmt_discoverable(u16 index, u8 discoverable)
2395{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002396 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002397 struct cmd_lookup match = { discoverable, NULL };
2398 int ret;
2399
Szymon Jancb8534e02011-03-01 16:55:34 +01002400 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002401
Johan Hedberg72a734e2010-12-30 00:38:22 +02002402 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002403
Szymon Janc4e51eae2011-02-25 19:05:48 +01002404 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2405 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002406
2407 if (match.sk)
2408 sock_put(match.sk);
2409
2410 return ret;
2411}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002412
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002413int mgmt_connectable(u16 index, u8 connectable)
2414{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002415 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002416 struct cmd_lookup match = { connectable, NULL };
2417 int ret;
2418
Johan Hedberg72a734e2010-12-30 00:38:22 +02002419 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002420
Johan Hedberg72a734e2010-12-30 00:38:22 +02002421 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002422
Szymon Janc4e51eae2011-02-25 19:05:48 +01002423 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002424
2425 if (match.sk)
2426 sock_put(match.sk);
2427
2428 return ret;
2429}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002430
Brian Gixa68668b2011-08-11 15:49:36 -07002431int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002432{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002433 struct mgmt_ev_new_key *ev;
2434 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002435
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002436 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2437 ev = kzalloc(total, GFP_ATOMIC);
2438 if (!ev)
2439 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002440
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002441 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002442 ev->key.addr_type = key->addr_type;
2443 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002444 memcpy(ev->key.val, key->val, 16);
2445 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002446 ev->key.auth = key->auth;
2447 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002448 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002449
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002450 memcpy(ev->key.data, key->data, key->dlen);
2451
2452 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2453
2454 kfree(ev);
2455
2456 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002457}
Johan Hedbergf7520542011-01-20 12:34:39 +02002458
Brian Gix2e2f50d2011-09-13 12:36:04 -07002459int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002460{
2461 struct mgmt_ev_connected ev;
2462
Johan Hedbergf7520542011-01-20 12:34:39 +02002463 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002464 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002465
Szymon Janc4e51eae2011-02-25 19:05:48 +01002466 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002467}
2468
Johan Hedberg8962ee72011-01-20 12:40:27 +02002469static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2470{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002471 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002472 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002473 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002474
Johan Hedberga38528f2011-01-22 06:46:43 +02002475 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002476
Szymon Janc4e51eae2011-02-25 19:05:48 +01002477 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002478
2479 *sk = cmd->sk;
2480 sock_hold(*sk);
2481
Johan Hedberga664b5b2011-02-19 12:06:02 -03002482 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002483}
2484
Johan Hedbergf7520542011-01-20 12:34:39 +02002485int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2486{
2487 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002488 struct sock *sk = NULL;
2489 int err;
2490
2491 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002492
Johan Hedbergf7520542011-01-20 12:34:39 +02002493 bacpy(&ev.bdaddr, bdaddr);
2494
Szymon Janc4e51eae2011-02-25 19:05:48 +01002495 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002496
2497 if (sk)
2498 sock_put(sk);
2499
2500 return err;
2501}
2502
2503int mgmt_disconnect_failed(u16 index)
2504{
2505 struct pending_cmd *cmd;
2506 int err;
2507
2508 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2509 if (!cmd)
2510 return -ENOENT;
2511
Szymon Janc4e51eae2011-02-25 19:05:48 +01002512 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002513
Johan Hedberga664b5b2011-02-19 12:06:02 -03002514 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002515
2516 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002517}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002518
2519int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2520{
2521 struct mgmt_ev_connect_failed ev;
2522
Johan Hedberg17d5c042011-01-22 06:09:08 +02002523 bacpy(&ev.bdaddr, bdaddr);
2524 ev.status = status;
2525
Szymon Janc4e51eae2011-02-25 19:05:48 +01002526 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002527}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530{
2531 struct mgmt_ev_pin_code_request ev;
2532
Brian Gixa68668b2011-08-11 15:49:36 -07002533 BT_DBG("hci%u", index);
2534
Johan Hedberg980e1a52011-01-22 06:10:07 +02002535 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002536 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002537
Szymon Janc4e51eae2011-02-25 19:05:48 +01002538 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2539 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002540}
2541
2542int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2543{
2544 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002545 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002546 int err;
2547
2548 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2549 if (!cmd)
2550 return -ENOENT;
2551
Johan Hedbergac56fb12011-02-19 12:05:59 -03002552 bacpy(&rp.bdaddr, bdaddr);
2553 rp.status = status;
2554
Szymon Janc4e51eae2011-02-25 19:05:48 +01002555 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2556 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002557
Johan Hedberga664b5b2011-02-19 12:06:02 -03002558 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002559
2560 return err;
2561}
2562
2563int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2564{
2565 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002566 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002567 int err;
2568
2569 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2570 if (!cmd)
2571 return -ENOENT;
2572
Johan Hedbergac56fb12011-02-19 12:05:59 -03002573 bacpy(&rp.bdaddr, bdaddr);
2574 rp.status = status;
2575
Szymon Janc4e51eae2011-02-25 19:05:48 +01002576 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2577 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002578
Johan Hedberga664b5b2011-02-19 12:06:02 -03002579 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002580
2581 return err;
2582}
Johan Hedberga5c29682011-02-19 12:05:57 -03002583
Brian Gixa68668b2011-08-11 15:49:36 -07002584int mgmt_user_confirm_request(u16 index, u8 event,
2585 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002586{
2587 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002588 struct hci_conn *conn = NULL;
2589 struct hci_dev *hdev;
2590 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2591
2592 BT_DBG("hci%u", index);
2593
2594 hdev = hci_dev_get(index);
2595
Brian Gix64bd5302011-09-08 11:35:48 -07002596 if (!hdev)
2597 return -ENODEV;
2598
Brian Gix64bd5302011-09-08 11:35:48 -07002599 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002600
2601 ev.auto_confirm = 0;
2602
2603 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2604 goto no_auto_confirm;
2605
2606 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2607 rem_cap = conn->remote_cap;
2608 loc_mitm = conn->auth_type & 0x01;
2609 rem_mitm = conn->remote_auth & 0x01;
2610
Brian Gixdbf59292011-11-11 15:45:17 -08002611 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2612 conn->auth_initiator && rem_cap == 0x03)
2613 ev.auto_confirm = 1;
2614 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
Brian Gixa68668b2011-08-11 15:49:36 -07002615 goto no_auto_confirm;
2616
2617
2618 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2619 ev.auto_confirm = 1;
2620
2621no_auto_confirm:
2622 bacpy(&ev.bdaddr, bdaddr);
2623 ev.event = event;
2624 put_unaligned_le32(value, &ev.value);
2625
Brian Gix64bd5302011-09-08 11:35:48 -07002626 hci_dev_put(hdev);
2627
Brian Gixa68668b2011-08-11 15:49:36 -07002628 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2629 NULL);
2630}
2631
2632int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2633{
2634 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002635
2636 BT_DBG("hci%u", index);
2637
Johan Hedberga5c29682011-02-19 12:05:57 -03002638 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002639
Brian Gixa68668b2011-08-11 15:49:36 -07002640 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002641 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002642}
2643
2644static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2645 u8 opcode)
2646{
2647 struct pending_cmd *cmd;
2648 struct mgmt_rp_user_confirm_reply rp;
2649 int err;
2650
2651 cmd = mgmt_pending_find(opcode, index);
2652 if (!cmd)
2653 return -ENOENT;
2654
Johan Hedberga5c29682011-02-19 12:05:57 -03002655 bacpy(&rp.bdaddr, bdaddr);
2656 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002657 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002658
Johan Hedberga664b5b2011-02-19 12:06:02 -03002659 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002660
2661 return err;
2662}
2663
2664int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2665{
2666 return confirm_reply_complete(index, bdaddr, status,
2667 MGMT_OP_USER_CONFIRM_REPLY);
2668}
2669
Szymon Jancb8534e02011-03-01 16:55:34 +01002670int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002671{
2672 return confirm_reply_complete(index, bdaddr, status,
2673 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2674}
Johan Hedberg2a611692011-02-19 12:06:00 -03002675
2676int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2677{
2678 struct mgmt_ev_auth_failed ev;
2679
Johan Hedberg2a611692011-02-19 12:06:00 -03002680 bacpy(&ev.bdaddr, bdaddr);
2681 ev.status = status;
2682
Szymon Janc4e51eae2011-02-25 19:05:48 +01002683 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002684}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002685
2686int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2687{
2688 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002689 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002690 struct mgmt_cp_set_local_name ev;
2691 int err;
2692
2693 memset(&ev, 0, sizeof(ev));
2694 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2695
2696 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2697 if (!cmd)
2698 goto send_event;
2699
2700 if (status) {
2701 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2702 goto failed;
2703 }
2704
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002705 hdev = hci_dev_get(index);
2706 if (hdev) {
2707 hci_dev_lock_bh(hdev);
2708 update_eir(hdev);
2709 hci_dev_unlock_bh(hdev);
2710 hci_dev_put(hdev);
2711 }
2712
Johan Hedbergb312b1612011-03-16 14:29:37 +02002713 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2714 sizeof(ev));
2715 if (err < 0)
2716 goto failed;
2717
2718send_event:
2719 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2720 cmd ? cmd->sk : NULL);
2721
2722failed:
2723 if (cmd)
2724 mgmt_pending_remove(cmd);
2725 return err;
2726}
Szymon Jancc35938b2011-03-22 13:12:21 +01002727
2728int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2729 u8 status)
2730{
2731 struct pending_cmd *cmd;
2732 int err;
2733
2734 BT_DBG("hci%u status %u", index, status);
2735
2736 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2737 if (!cmd)
2738 return -ENOENT;
2739
2740 if (status) {
2741 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2742 EIO);
2743 } else {
2744 struct mgmt_rp_read_local_oob_data rp;
2745
2746 memcpy(rp.hash, hash, sizeof(rp.hash));
2747 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2748
2749 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2750 &rp, sizeof(rp));
2751 }
2752
2753 mgmt_pending_remove(cmd);
2754
2755 return err;
2756}
Johan Hedberge17acd42011-03-30 23:57:16 +03002757
Brian Gixa68668b2011-08-11 15:49:36 -07002758int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2759 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002760{
2761 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002762 struct pending_cmd *cmd;
2763 int err;
2764
2765 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002766
2767 memset(&ev, 0, sizeof(ev));
2768
2769 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002770 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002771 ev.type = type;
2772 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002773
Brian Gixa68668b2011-08-11 15:49:36 -07002774 if (dev_class)
2775 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002776
Brian Gixa68668b2011-08-11 15:49:36 -07002777 if (eir && eir_len)
2778 memcpy(ev.eir, eir, eir_len);
2779
2780 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2781
2782 if (err < 0)
2783 return err;
2784
2785 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2786 if (cmd) {
2787 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002788 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002789
2790 ilp->int_count++;
2791 if (hdev && ilp->int_count >= ilp->int_phase) {
2792 /* Inquiry scan for General Discovery LAP */
2793 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2794 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002795
Brian Gixa68668b2011-08-11 15:49:36 -07002796 ilp->int_phase *= 2;
2797 ilp->int_count = 0;
2798 if (ilp->mode == SCAN_LE) {
2799 /* cancel LE scan */
2800 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2801 sizeof(le_cp), &le_cp);
2802 /* start BR scan */
2803 cp.num_rsp = (u8) ilp->int_phase;
2804 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2805 sizeof(cp), &cp);
2806 ilp->mode = SCAN_BR;
2807 del_timer_sync(&ilp->le_timer);
2808 }
2809 }
Brian Gix64bd5302011-09-08 11:35:48 -07002810
2811 if (hdev)
2812 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002813 }
2814
2815 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002816}
Johan Hedberga88a9652011-03-30 13:18:12 +03002817
Brian Gixa68668b2011-08-11 15:49:36 -07002818
2819int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002820{
2821 struct mgmt_ev_remote_name ev;
2822
2823 memset(&ev, 0, sizeof(ev));
2824
2825 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002826 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002827 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2828
2829 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2830}