blob: 6e5d9fc92fad4d721cb52fb9f34f308c413e757b [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
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05301333static int encrypt_link(struct sock *sk, u16 index, unsigned char *data,
1334 u16 len)
1335{
1336 struct hci_dev *hdev;
1337 struct mgmt_cp_encrypt_link *cp;
1338 struct hci_cp_set_conn_encrypt enc;
1339 struct hci_conn *conn;
1340 int err = 0;
1341
1342 BT_DBG("");
1343
1344 cp = (void *) data;
1345
1346 if (len != sizeof(*cp))
1347 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINVAL);
1348
1349 hdev = hci_dev_get(index);
1350 if (!hdev)
1351 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV);
1352
1353 hci_dev_lock(hdev);
1354
1355 if (!test_bit(HCI_UP, &hdev->flags)) {
1356 err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN);
1357 goto failed;
1358 }
1359
1360 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1361 &cp->bdaddr);
1362 if (!conn)
1363 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN);
1364
1365 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
1366 return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS);
1367
1368 if (conn->link_mode & HCI_LM_AUTH) {
1369 enc.handle = cpu_to_le16(conn->handle);
1370 enc.encrypt = cp->enable;
1371 err = hci_send_cmd(hdev,
1372 HCI_OP_SET_CONN_ENCRYPT, sizeof(enc), &enc);
1373 } else {
1374 conn->auth_initiator = 1;
1375 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1376 struct hci_cp_auth_requested cp;
1377 cp.handle = cpu_to_le16(conn->handle);
1378 err = hci_send_cmd(conn->hdev,
1379 HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
1380 }
1381 }
1382
1383failed:
1384 hci_dev_unlock(hdev);
1385 hci_dev_put(hdev);
1386
1387 return err;
1388}
1389
1390
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1392 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393{
1394 struct hci_dev *hdev;
1395 struct mgmt_cp_pin_code_neg_reply *cp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001397 int err;
1398
1399 BT_DBG("");
1400
1401 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001402
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001403 if (len != sizeof(*cp))
1404 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1405 EINVAL);
1406
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001408 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001409 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1410 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001413
1414 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1416 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417 goto failed;
1418 }
1419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
1421 data, len);
1422 if (!cmd) {
1423 err = -ENOMEM;
1424 goto failed;
1425 }
1426
1427 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1428 &cp->bdaddr);
1429 if (err < 0)
1430 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001431
1432failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001434 hci_dev_put(hdev);
1435
1436 return err;
1437}
1438
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1440 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001441{
1442 struct hci_dev *hdev;
1443 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001444
1445 BT_DBG("");
1446
1447 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001448
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001450 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001453 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001454 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001457
1458 hdev->io_capability = cp->io_capability;
1459
1460 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001461 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001464 hci_dev_put(hdev);
1465
Szymon Janc4e51eae2011-02-25 19:05:48 +01001466 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001467}
1468
Johan Hedberge9a416b2011-02-19 12:05:56 -03001469static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1470{
1471 struct hci_dev *hdev = conn->hdev;
1472 struct list_head *p;
1473
1474 list_for_each(p, &cmd_list) {
1475 struct pending_cmd *cmd;
1476
1477 cmd = list_entry(p, struct pending_cmd, list);
1478
1479 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1480 continue;
1481
1482 if (cmd->index != hdev->id)
1483 continue;
1484
1485 if (cmd->user_data != conn)
1486 continue;
1487
1488 return cmd;
1489 }
1490
1491 return NULL;
1492}
1493
1494static void pairing_complete(struct pending_cmd *cmd, u8 status)
1495{
1496 struct mgmt_rp_pair_device rp;
1497 struct hci_conn *conn = cmd->user_data;
1498
Brian Gixa68668b2011-08-11 15:49:36 -07001499 BT_DBG(" %u", status);
1500
Johan Hedberge9a416b2011-02-19 12:05:56 -03001501 bacpy(&rp.bdaddr, &conn->dst);
1502 rp.status = status;
1503
Szymon Janc4e51eae2011-02-25 19:05:48 +01001504 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001505
1506 /* So we don't get further callbacks for this connection */
1507 conn->connect_cfm_cb = NULL;
1508 conn->security_cfm_cb = NULL;
1509 conn->disconn_cfm_cb = NULL;
1510
Johan Hedberga664b5b2011-02-19 12:06:02 -03001511 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001512}
1513
1514static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1515{
1516 struct pending_cmd *cmd;
1517
Brian Gixa68668b2011-08-11 15:49:36 -07001518 BT_DBG(" %u", status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519
1520 cmd = find_pairing(conn);
1521 if (!cmd) {
1522 BT_DBG("Unable to find a pending command");
1523 return;
1524 }
1525
1526 pairing_complete(cmd, status);
1527}
1528
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001529static void pairing_security_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001530{
1531 struct pending_cmd *cmd;
1532
1533 BT_DBG(" %u", status);
1534
1535 cmd = find_pairing(conn);
1536 if (!cmd) {
1537 BT_DBG("Unable to find a pending command");
1538 return;
1539 }
1540
1541 if (conn->type == LE_LINK)
1542 smp_link_encrypt_cmplt(conn->l2cap_data, status,
1543 status ? 0 : 1);
1544 else
1545 pairing_complete(cmd, status);
1546}
1547
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001548static void pairing_connect_complete_cb(struct hci_conn *conn, u8 status)
Brian Gixa68668b2011-08-11 15:49:36 -07001549{
1550 struct pending_cmd *cmd;
1551
1552 BT_DBG("conn: %p %u", conn, status);
1553
1554 cmd = find_pairing(conn);
1555 if (!cmd) {
1556 BT_DBG("Unable to find a pending command");
1557 return;
1558 }
Brian Gix114f3a62011-09-27 14:02:20 -07001559
1560 if (status)
1561 pairing_complete(cmd, status);
1562
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001563 hci_conn_put(conn);
Brian Gixa68668b2011-08-11 15:49:36 -07001564}
1565
1566static void discovery_terminated(struct pending_cmd *cmd, void *data)
1567{
1568 struct mgmt_mode ev = {0};
1569 struct disco_interleave *ilp = cmd->param;
1570
1571 BT_DBG("");
1572 del_timer_sync(&ilp->le_timer);
1573 del_timer_sync(&ilp->timer);
1574 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1575
1576 list_del(&cmd->list);
1577
1578 mgmt_pending_free(cmd);
1579}
1580
Szymon Janc4e51eae2011-02-25 19:05:48 +01001581static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001582{
1583 struct hci_dev *hdev;
1584 struct mgmt_cp_pair_device *cp;
1585 struct pending_cmd *cmd;
Brian Gixa68668b2011-08-11 15:49:36 -07001586 u8 sec_level, auth_type, io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001587 struct hci_conn *conn;
Brian Gixfdd38922011-09-28 16:23:48 -07001588 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001589 int err;
1590
1591 BT_DBG("");
1592
Brian Gix64bd5302011-09-08 11:35:48 -07001593 cp = (void *) data;
1594
1595 if (len != sizeof(*cp))
1596 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1597
Szymon Janc4e51eae2011-02-25 19:05:48 +01001598 hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07001599
Johan Hedberge9a416b2011-02-19 12:05:56 -03001600 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001601 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001604
Prabhakaran Mc6001a712011-09-06 11:56:25 +05301605 BT_DBG("SSP Cap is %d", cp->ssp_cap);
1606 io_cap = cp->io_cap;
1607 if ((cp->ssp_cap == 0) || (io_cap == 0x03)) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001608 sec_level = BT_SECURITY_MEDIUM;
1609 auth_type = HCI_AT_DEDICATED_BONDING;
1610 } else {
1611 sec_level = BT_SECURITY_HIGH;
1612 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1613 }
1614
Brian Gixfdd38922011-09-28 16:23:48 -07001615 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1616 if (entry && entry->flags & 0x04) {
Brian Gixa68668b2011-08-11 15:49:36 -07001617 conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
1618 auth_type);
Brian Gixa68668b2011-08-11 15:49:36 -07001619 } else {
1620 /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
1621 if (io_cap == 0x04)
1622 io_cap = 0x01;
1623 conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level,
1624 auth_type);
1625 }
1626
Ville Tervo30e76272011-02-22 16:10:53 -03001627 if (IS_ERR(conn)) {
1628 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001629 goto unlock;
1630 }
1631
1632 if (conn->connect_cfm_cb) {
1633 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001634 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001635 goto unlock;
1636 }
1637
Szymon Janc4e51eae2011-02-25 19:05:48 +01001638 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001639 if (!cmd) {
1640 err = -ENOMEM;
1641 hci_conn_put(conn);
1642 goto unlock;
1643 }
1644
Brian Gix6d5fb8a2011-09-09 14:53:04 -07001645 conn->connect_cfm_cb = pairing_connect_complete_cb;
1646 conn->security_cfm_cb = pairing_security_complete_cb;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001647 conn->disconn_cfm_cb = pairing_complete_cb;
Brian Gixa68668b2011-08-11 15:49:36 -07001648 conn->io_capability = io_cap;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001649 cmd->user_data = conn;
1650
1651 if (conn->state == BT_CONNECTED &&
1652 hci_conn_security(conn, sec_level, auth_type))
1653 pairing_complete(cmd, 0);
1654
1655 err = 0;
1656
1657unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001658 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001659 hci_dev_put(hdev);
1660
1661 return err;
1662}
1663
Szymon Janc4e51eae2011-02-25 19:05:48 +01001664static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
Brian Gixa68668b2011-08-11 15:49:36 -07001665 u16 len, u16 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03001666{
1667 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Brian Gixa68668b2011-08-11 15:49:36 -07001668 u16 mgmt_op = opcode, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001669 struct pending_cmd *cmd;
1670 struct hci_dev *hdev;
Brian Gixa68668b2011-08-11 15:49:36 -07001671 struct hci_conn *le_conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001672 int err;
1673
Brian Gixa68668b2011-08-11 15:49:36 -07001674 BT_DBG("%d", mgmt_op);
Johan Hedberga5c29682011-02-19 12:05:57 -03001675
Brian Gixa68668b2011-08-11 15:49:36 -07001676 if (mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY)
Johan Hedberga5c29682011-02-19 12:05:57 -03001677 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
Brian Gixa68668b2011-08-11 15:49:36 -07001678 else
1679 hci_op = HCI_OP_USER_CONFIRM_REPLY;
Johan Hedberga5c29682011-02-19 12:05:57 -03001680
Brian Gixa68668b2011-08-11 15:49:36 -07001681 if (len < sizeof(*cp))
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001682 return cmd_status(sk, index, mgmt_op, EINVAL);
1683
Szymon Janc4e51eae2011-02-25 19:05:48 +01001684 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001685 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001686 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001689
Johan Hedberga5c29682011-02-19 12:05:57 -03001690 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001691 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Brian Gixa68668b2011-08-11 15:49:36 -07001692 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001693 }
1694
Brian Gixa68668b2011-08-11 15:49:36 -07001695 le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1696 if (le_conn) {
1697 err = le_user_confirm_reply(le_conn, mgmt_op, (void *) cp);
1698 goto done;
1699 }
1700 BT_DBG("BR/EDR: %s", mgmt_op == MGMT_OP_USER_CONFIRM_NEG_REPLY ?
1701 "Reject" : "Accept");
1702
Szymon Janc4e51eae2011-02-25 19:05:48 +01001703 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001704 if (!cmd) {
1705 err = -ENOMEM;
Brian Gixa68668b2011-08-11 15:49:36 -07001706 goto done;
1707 }
1708
1709 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
1710 if (err < 0)
1711 mgmt_pending_remove(cmd);
1712
1713done:
1714 hci_dev_unlock(hdev);
1715 hci_dev_put(hdev);
1716
1717 return err;
1718}
1719
1720static int resolve_name(struct sock *sk, u16 index, unsigned char *data,
1721 u16 len)
1722{
1723 struct mgmt_cp_resolve_name *mgmt_cp = (void *) data;
1724 struct hci_cp_remote_name_req hci_cp;
1725 struct hci_dev *hdev;
1726 struct pending_cmd *cmd;
1727 int err;
1728
1729 BT_DBG("");
1730
1731 if (len != sizeof(*mgmt_cp))
1732 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, EINVAL);
1733
1734 hdev = hci_dev_get(index);
1735 if (!hdev)
1736 return cmd_status(sk, index, MGMT_OP_RESOLVE_NAME, ENODEV);
1737
1738 hci_dev_lock(hdev);
1739
1740 cmd = mgmt_pending_add(sk, MGMT_OP_RESOLVE_NAME, index, data, len);
1741 if (!cmd) {
1742 err = -ENOMEM;
Johan Hedberga5c29682011-02-19 12:05:57 -03001743 goto failed;
1744 }
1745
Brian Gixa68668b2011-08-11 15:49:36 -07001746 memset(&hci_cp, 0, sizeof(hci_cp));
1747 bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
1748 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(hci_cp),
1749 &hci_cp);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001750 if (err < 0)
1751 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001752
1753failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001755 hci_dev_put(hdev);
1756
1757 return err;
1758}
1759
Brian Gix7f7e16c2011-11-01 16:27:25 -07001760static int set_connection_params(struct sock *sk, u16 index,
1761 unsigned char *data, u16 len)
1762{
1763 struct mgmt_cp_set_connection_params *cp = (void *) data;
1764 struct hci_dev *hdev;
1765 struct hci_conn *conn;
1766 int err;
1767
1768 BT_DBG("");
1769
1770 if (len != sizeof(*cp))
1771 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1772 EINVAL);
1773
1774 hdev = hci_dev_get(index);
1775 if (!hdev)
1776 return cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1777 ENODEV);
1778
1779 hci_dev_lock(hdev);
1780
1781 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1782 if (!conn) {
1783 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS,
1784 ENOTCONN);
1785 goto failed;
1786 }
1787
1788 hci_le_conn_update(conn, le16_to_cpu(cp->interval_min),
1789 le16_to_cpu(cp->interval_max),
1790 le16_to_cpu(cp->slave_latency),
1791 le16_to_cpu(cp->timeout_multiplier));
1792
1793 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTION_PARAMS, 0);
1794
1795failed:
1796 hci_dev_unlock(hdev);
1797 hci_dev_put(hdev);
1798
1799 return err;
1800}
1801
Johan Hedbergb312b1612011-03-16 14:29:37 +02001802static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1803 u16 len)
1804{
1805 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1806 struct hci_cp_write_local_name hci_cp;
1807 struct hci_dev *hdev;
1808 struct pending_cmd *cmd;
1809 int err;
1810
1811 BT_DBG("");
1812
1813 if (len != sizeof(*mgmt_cp))
1814 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1815
1816 hdev = hci_dev_get(index);
1817 if (!hdev)
1818 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001821
1822 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1823 if (!cmd) {
1824 err = -ENOMEM;
1825 goto failed;
1826 }
1827
1828 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1829 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1830 &hci_cp);
1831 if (err < 0)
1832 mgmt_pending_remove(cmd);
1833
1834failed:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001836 hci_dev_put(hdev);
1837
1838 return err;
1839}
1840
Brian Gixa68668b2011-08-11 15:49:36 -07001841static void discovery_rsp(struct pending_cmd *cmd, void *data)
1842{
1843 struct mgmt_mode ev;
1844
1845 BT_DBG("");
1846 if (cmd->opcode == MGMT_OP_START_DISCOVERY) {
1847 ev.val = 1;
1848 cmd_status(cmd->sk, cmd->index, MGMT_OP_START_DISCOVERY, 0);
1849 } else {
1850 ev.val = 0;
1851 cmd_complete(cmd->sk, cmd->index, MGMT_OP_STOP_DISCOVERY,
1852 NULL, 0);
1853 if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
1854 struct disco_interleave *ilp = cmd->param;
1855
1856 del_timer_sync(&ilp->le_timer);
1857 del_timer_sync(&ilp->timer);
1858 }
1859 }
1860
1861 mgmt_event(MGMT_EV_DISCOVERING, cmd->index, &ev, sizeof(ev), NULL);
1862
1863 list_del(&cmd->list);
1864
1865 mgmt_pending_free(cmd);
1866}
1867
1868void mgmt_inquiry_started(u16 index)
1869{
1870 BT_DBG("");
1871 mgmt_pending_foreach(MGMT_OP_START_DISCOVERY, index,
1872 discovery_rsp, NULL);
1873}
1874
1875void mgmt_inquiry_complete_evt(u16 index, u8 status)
1876{
1877 struct hci_dev *hdev;
1878 struct hci_cp_le_set_scan_enable le_cp = {1, 0};
1879 struct pending_cmd *cmd;
1880 int err = -1;
1881
1882 BT_DBG("");
1883
1884 hdev = hci_dev_get(index);
Brian Gix64bd5302011-09-08 11:35:48 -07001885
1886 if (hdev)
1887 hci_dev_lock(hdev);
1888
Brian Gixa68668b2011-08-11 15:49:36 -07001889 if (!hdev || !lmp_le_capable(hdev)) {
1890 struct mgmt_mode cp = {0};
1891
1892 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1893 discovery_terminated, NULL);
1894
1895 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001896
Brian Gix64bd5302011-09-08 11:35:48 -07001897 if (hdev)
1898 goto done;
1899 else
1900 return;
1901 }
Brian Gixa68668b2011-08-11 15:49:36 -07001902
1903 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1904 if (cmd && cmd->param) {
1905 struct disco_interleave *ilp = cmd->param;
1906
1907 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1908 sizeof(le_cp), &le_cp);
1909 if (err >= 0) {
1910 mod_timer(&ilp->le_timer, jiffies +
1911 msecs_to_jiffies(ilp->int_phase * 1000));
1912 ilp->mode = SCAN_LE;
1913 } else
1914 ilp->mode = SCAN_IDLE;
1915 }
1916
1917 if (err < 0)
1918 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1919 discovery_terminated, NULL);
1920
Brian Gix64bd5302011-09-08 11:35:48 -07001921done:
Brian Gixa68668b2011-08-11 15:49:36 -07001922 hci_dev_unlock(hdev);
1923 hci_dev_put(hdev);
1924}
1925
1926static void disco_to(unsigned long data)
1927{
1928 struct disco_interleave *ilp = (void *)data;
1929 struct hci_dev *hdev;
1930 struct pending_cmd *cmd;
1931
1932 BT_DBG("hci%d", ilp->index);
1933
1934 del_timer_sync(&ilp->le_timer);
1935 hdev = hci_dev_get(ilp->index);
1936
1937 if (hdev) {
1938 hci_dev_lock(hdev);
1939
1940 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1941
1942 if (ilp->mode != SCAN_IDLE) {
1943 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1944
1945 if (ilp->mode == SCAN_LE)
1946 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1947 sizeof(le_cp), &le_cp);
1948 else
1949 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1950 0, NULL);
1951
1952 ilp->mode = SCAN_IDLE;
1953 }
1954
1955 if (cmd) {
1956 struct mgmt_mode cp = {0};
1957
1958 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1959 sizeof(cp), NULL);
1960 mgmt_pending_remove(cmd);
1961 }
1962
1963 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001964 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001965 }
1966}
1967
1968static void disco_le_to(unsigned long data)
1969{
1970 struct disco_interleave *ilp = (void *)data;
1971 struct hci_dev *hdev;
1972 struct pending_cmd *cmd;
1973 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1974
1975 BT_DBG("hci%d", ilp->index);
1976
1977 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001978
1979 if (hdev) {
1980 hci_dev_lock(hdev);
1981
1982 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1983
1984 if (ilp->mode == SCAN_LE)
1985 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1986 sizeof(le_cp), &le_cp);
1987
1988 /* re-start BR scan */
1989 if (cmd) {
1990 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1991 ilp->int_phase *= 2;
1992 ilp->int_count = 0;
1993 cp.num_rsp = (u8) ilp->int_phase;
1994 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1995 ilp->mode = SCAN_BR;
1996 } else
1997 ilp->mode = SCAN_IDLE;
1998
1999 hci_dev_unlock(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07002000 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002001 }
2002}
2003
2004static int start_discovery(struct sock *sk, u16 index)
2005{
2006 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2007 struct hci_dev *hdev;
2008 struct pending_cmd *cmd;
2009 int err;
2010
2011 BT_DBG("");
2012
2013 hdev = hci_dev_get(index);
2014 if (!hdev)
2015 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2016
2017 hci_dev_lock(hdev);
2018
2019 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2020 if (!cmd) {
2021 err = -ENOMEM;
2022 goto failed;
2023 }
2024
2025 /* If LE Capable, we will alternate between BR/EDR and LE */
2026 if (lmp_le_capable(hdev)) {
2027 struct hci_cp_le_set_scan_parameters le_cp;
2028
2029 /* Shorten BR scan params */
2030 cp.num_rsp = 1;
2031 cp.length /= 2;
2032
2033 /* Setup LE scan params */
2034 memset(&le_cp, 0, sizeof(le_cp));
2035 le_cp.type = 0x01; /* Active scanning */
2036 /* The recommended value for scan interval and window is
2037 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2038 le_cp.interval = cpu_to_le16(0x0012);
2039 le_cp.window = cpu_to_le16(0x0012);
2040 le_cp.own_bdaddr_type = 0; /* Public address */
2041 le_cp.filter = 0; /* Accept all adv packets */
2042
2043 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2044 sizeof(le_cp), &le_cp);
2045 }
2046
2047 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2048
2049 if (err < 0)
2050 mgmt_pending_remove(cmd);
2051 else if (lmp_le_capable(hdev)) {
2052 struct disco_interleave il, *ilp;
2053
2054 il.int_phase = 1;
2055 il.int_count = 0;
2056 il.index = index;
2057 il.mode = SCAN_BR;
2058 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
2059 sizeof(struct disco_interleave));
2060 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2061 if (cmd) {
2062 ilp = cmd->param;
2063 setup_timer(&ilp->le_timer, disco_le_to,
2064 (unsigned long) ilp);
2065 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
2066 mod_timer(&ilp->timer,
2067 jiffies + msecs_to_jiffies(20000));
2068 }
2069 }
2070
2071failed:
2072 hci_dev_unlock(hdev);
2073 hci_dev_put(hdev);
2074
2075 return err;
2076}
2077
2078static int stop_discovery(struct sock *sk, u16 index)
2079{
2080 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2081 struct mgmt_mode mode_cp = {0};
2082 struct disco_interleave *ilp = NULL;
2083 struct hci_dev *hdev;
2084 struct pending_cmd *cmd = NULL;
2085 int err = -EPERM;
2086
2087 BT_DBG("");
2088
2089 hdev = hci_dev_get(index);
2090 if (!hdev)
2091 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2092
2093 hci_dev_lock(hdev);
2094
2095 if (lmp_le_capable(hdev)) {
2096 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2097 if (!cmd) {
2098 err = -ENOMEM;
2099 goto failed;
2100 }
2101
2102 ilp = cmd->param;
2103 }
2104
2105 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2106 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2107 sizeof(le_cp), &le_cp);
2108
2109 if (err < 0) {
2110 if (!ilp || (ilp->mode == SCAN_BR))
2111 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2112 0, NULL);
2113 }
2114
2115 if (ilp) {
2116 ilp->mode = SCAN_IDLE;
2117 del_timer_sync(&ilp->le_timer);
2118 del_timer_sync(&ilp->timer);
2119 }
2120
2121 if (err < 0 && cmd)
2122 mgmt_pending_remove(cmd);
2123
2124 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2125
2126failed:
2127 hci_dev_unlock(hdev);
2128 hci_dev_put(hdev);
2129
2130 if (err < 0)
2131 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2132 else
2133 return err;
2134}
2135
Szymon Jancc35938b2011-03-22 13:12:21 +01002136static int read_local_oob_data(struct sock *sk, u16 index)
2137{
2138 struct hci_dev *hdev;
2139 struct pending_cmd *cmd;
2140 int err;
2141
2142 BT_DBG("hci%u", index);
2143
2144 hdev = hci_dev_get(index);
2145 if (!hdev)
2146 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2147 ENODEV);
2148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002150
2151 if (!test_bit(HCI_UP, &hdev->flags)) {
2152 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2153 ENETDOWN);
2154 goto unlock;
2155 }
2156
2157 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2158 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2159 EOPNOTSUPP);
2160 goto unlock;
2161 }
2162
2163 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2164 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2165 goto unlock;
2166 }
2167
2168 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2169 if (!cmd) {
2170 err = -ENOMEM;
2171 goto unlock;
2172 }
2173
2174 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2175 if (err < 0)
2176 mgmt_pending_remove(cmd);
2177
2178unlock:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 hci_dev_put(hdev);
2181
2182 return err;
2183}
2184
Szymon Janc2763eda2011-03-22 13:12:22 +01002185static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2186 u16 len)
2187{
2188 struct hci_dev *hdev;
2189 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2190 int err;
2191
2192 BT_DBG("hci%u ", index);
2193
2194 if (len != sizeof(*cp))
2195 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2196 EINVAL);
2197
2198 hdev = hci_dev_get(index);
2199 if (!hdev)
2200 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2201 ENODEV);
2202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002204
2205 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2206 cp->randomizer);
2207 if (err < 0)
2208 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2209 else
2210 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2211 0);
2212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002214 hci_dev_put(hdev);
2215
2216 return err;
2217}
2218
2219static int remove_remote_oob_data(struct sock *sk, u16 index,
2220 unsigned char *data, u16 len)
2221{
2222 struct hci_dev *hdev;
2223 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2224 int err;
2225
2226 BT_DBG("hci%u ", index);
2227
2228 if (len != sizeof(*cp))
2229 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2230 EINVAL);
2231
2232 hdev = hci_dev_get(index);
2233 if (!hdev)
2234 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2235 ENODEV);
2236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002238
2239 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2240 if (err < 0)
2241 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2242 -err);
2243 else
2244 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2245 NULL, 0);
2246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 hci_dev_unlock(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002248 hci_dev_put(hdev);
2249
2250 return err;
2251}
2252
Johan Hedberg03811012010-12-08 00:21:06 +02002253int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2254{
2255 unsigned char *buf;
2256 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002257 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002258 int err;
2259
2260 BT_DBG("got %zu bytes", msglen);
2261
2262 if (msglen < sizeof(*hdr))
2263 return -EINVAL;
2264
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002265 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002266 if (!buf)
2267 return -ENOMEM;
2268
2269 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2270 err = -EFAULT;
2271 goto done;
2272 }
2273
2274 hdr = (struct mgmt_hdr *) buf;
2275 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002276 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002277 len = get_unaligned_le16(&hdr->len);
2278
2279 if (len != msglen - sizeof(*hdr)) {
2280 err = -EINVAL;
2281 goto done;
2282 }
2283
Brian Gixa68668b2011-08-11 15:49:36 -07002284 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002285 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002286 case MGMT_OP_READ_VERSION:
2287 err = read_version(sk);
2288 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002289 case MGMT_OP_READ_INDEX_LIST:
2290 err = read_index_list(sk);
2291 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002292 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002294 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002295 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002296 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002297 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002298 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002299 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002300 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002301 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2302 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2303 len);
2304 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002305 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002306 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002307 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002308 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002309 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002310 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002311 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002312 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002313 break;
2314 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002315 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002316 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002317 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002318 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002319 break;
2320 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002321 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002322 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002323 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002324 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002325 break;
2326 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002327 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002328 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002329 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002330 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002332 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002333 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002334 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002335 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002336 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002337 break;
2338 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002339 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002340 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002341 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002342 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002343 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002344 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002345 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002346 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002347 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002348 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002349 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002350 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2351 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002352 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002353 case MGMT_OP_SET_LOCAL_NAME:
2354 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2355 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002356 case MGMT_OP_START_DISCOVERY:
2357 err = start_discovery(sk, index);
2358 break;
2359 case MGMT_OP_STOP_DISCOVERY:
2360 err = stop_discovery(sk, index);
2361 break;
2362 case MGMT_OP_RESOLVE_NAME:
2363 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2364 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002365 case MGMT_OP_SET_CONNECTION_PARAMS:
2366 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2367 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002368 case MGMT_OP_READ_LOCAL_OOB_DATA:
2369 err = read_local_oob_data(sk, index);
2370 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002371 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2372 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2373 break;
2374 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2375 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2376 len);
2377 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302378 case MGMT_OP_ENCRYPT_LINK:
2379 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2380 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381
Johan Hedberg03811012010-12-08 00:21:06 +02002382 default:
2383 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002384 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002385 break;
2386 }
2387
Johan Hedberge41d8b42010-12-13 21:07:03 +02002388 if (err < 0)
2389 goto done;
2390
Johan Hedberg03811012010-12-08 00:21:06 +02002391 err = msglen;
2392
2393done:
2394 kfree(buf);
2395 return err;
2396}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002397
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002398int mgmt_index_added(u16 index)
2399{
Brian Gixa68668b2011-08-11 15:49:36 -07002400 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002402}
2403
2404int mgmt_index_removed(u16 index)
2405{
Brian Gixa68668b2011-08-11 15:49:36 -07002406 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002407 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002408}
2409
Johan Hedberg73f22f62010-12-29 16:00:25 +02002410struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002411 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002412 struct sock *sk;
2413};
2414
Johan Hedberg72a734e2010-12-30 00:38:22 +02002415static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002416{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002417 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002418 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002419
Johan Hedberg72a734e2010-12-30 00:38:22 +02002420 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002421 return;
2422
Johan Hedberg053f0212011-01-26 13:07:10 +02002423 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002424
2425 list_del(&cmd->list);
2426
2427 if (match->sk == NULL) {
2428 match->sk = cmd->sk;
2429 sock_hold(match->sk);
2430 }
2431
2432 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002433}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002434
2435int mgmt_powered(u16 index, u8 powered)
2436{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002437 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002438 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002439 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002440
Brian Gixa68668b2011-08-11 15:49:36 -07002441 BT_DBG("hci%u %d", index, powered);
2442
Johan Hedberg72a734e2010-12-30 00:38:22 +02002443 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002444
Johan Hedberg72a734e2010-12-30 00:38:22 +02002445 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002446
Szymon Janc4e51eae2011-02-25 19:05:48 +01002447 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002448
2449 if (match.sk)
2450 sock_put(match.sk);
2451
2452 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002453}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002454
Johan Hedberg73f22f62010-12-29 16:00:25 +02002455int mgmt_discoverable(u16 index, u8 discoverable)
2456{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002457 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002458 struct cmd_lookup match = { discoverable, NULL };
2459 int ret;
2460
Szymon Jancb8534e02011-03-01 16:55:34 +01002461 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002462
Johan Hedberg72a734e2010-12-30 00:38:22 +02002463 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002464
Szymon Janc4e51eae2011-02-25 19:05:48 +01002465 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2466 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002467
2468 if (match.sk)
2469 sock_put(match.sk);
2470
2471 return ret;
2472}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002473
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002474int mgmt_connectable(u16 index, u8 connectable)
2475{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002476 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002477 struct cmd_lookup match = { connectable, NULL };
2478 int ret;
2479
Johan Hedberg72a734e2010-12-30 00:38:22 +02002480 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002481
Johan Hedberg72a734e2010-12-30 00:38:22 +02002482 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002483
Szymon Janc4e51eae2011-02-25 19:05:48 +01002484 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002485
2486 if (match.sk)
2487 sock_put(match.sk);
2488
2489 return ret;
2490}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002491
Brian Gixa68668b2011-08-11 15:49:36 -07002492int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002493{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002494 struct mgmt_ev_new_key *ev;
2495 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002496
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002497 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2498 ev = kzalloc(total, GFP_ATOMIC);
2499 if (!ev)
2500 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002501
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002502 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002503 ev->key.addr_type = key->addr_type;
2504 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002505 memcpy(ev->key.val, key->val, 16);
2506 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002507 ev->key.auth = key->auth;
2508 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002509 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002510
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002511 memcpy(ev->key.data, key->data, key->dlen);
2512
2513 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2514
2515 kfree(ev);
2516
2517 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002518}
Johan Hedbergf7520542011-01-20 12:34:39 +02002519
Brian Gix2e2f50d2011-09-13 12:36:04 -07002520int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002521{
2522 struct mgmt_ev_connected ev;
2523
Johan Hedbergf7520542011-01-20 12:34:39 +02002524 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002525 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002526
Szymon Janc4e51eae2011-02-25 19:05:48 +01002527 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002528}
2529
Johan Hedberg8962ee72011-01-20 12:40:27 +02002530static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2531{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002532 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002533 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002534 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002535
Johan Hedberga38528f2011-01-22 06:46:43 +02002536 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002537
Szymon Janc4e51eae2011-02-25 19:05:48 +01002538 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002539
2540 *sk = cmd->sk;
2541 sock_hold(*sk);
2542
Johan Hedberga664b5b2011-02-19 12:06:02 -03002543 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002544}
2545
Johan Hedbergf7520542011-01-20 12:34:39 +02002546int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2547{
2548 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002549 struct sock *sk = NULL;
2550 int err;
2551
2552 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002553
Johan Hedbergf7520542011-01-20 12:34:39 +02002554 bacpy(&ev.bdaddr, bdaddr);
2555
Szymon Janc4e51eae2011-02-25 19:05:48 +01002556 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557
2558 if (sk)
2559 sock_put(sk);
2560
2561 return err;
2562}
2563
2564int mgmt_disconnect_failed(u16 index)
2565{
2566 struct pending_cmd *cmd;
2567 int err;
2568
2569 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2570 if (!cmd)
2571 return -ENOENT;
2572
Szymon Janc4e51eae2011-02-25 19:05:48 +01002573 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002574
Johan Hedberga664b5b2011-02-19 12:06:02 -03002575 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002576
2577 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002578}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002579
2580int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2581{
2582 struct mgmt_ev_connect_failed ev;
2583
Johan Hedberg17d5c042011-01-22 06:09:08 +02002584 bacpy(&ev.bdaddr, bdaddr);
2585 ev.status = status;
2586
Szymon Janc4e51eae2011-02-25 19:05:48 +01002587 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002588}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002591{
2592 struct mgmt_ev_pin_code_request ev;
2593
Brian Gixa68668b2011-08-11 15:49:36 -07002594 BT_DBG("hci%u", index);
2595
Johan Hedberg980e1a52011-01-22 06:10:07 +02002596 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002597 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002598
Szymon Janc4e51eae2011-02-25 19:05:48 +01002599 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2600 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002601}
2602
2603int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2604{
2605 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002606 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002607 int err;
2608
2609 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2610 if (!cmd)
2611 return -ENOENT;
2612
Johan Hedbergac56fb12011-02-19 12:05:59 -03002613 bacpy(&rp.bdaddr, bdaddr);
2614 rp.status = status;
2615
Szymon Janc4e51eae2011-02-25 19:05:48 +01002616 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2617 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002618
Johan Hedberga664b5b2011-02-19 12:06:02 -03002619 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002620
2621 return err;
2622}
2623
2624int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2625{
2626 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002627 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002628 int err;
2629
2630 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2631 if (!cmd)
2632 return -ENOENT;
2633
Johan Hedbergac56fb12011-02-19 12:05:59 -03002634 bacpy(&rp.bdaddr, bdaddr);
2635 rp.status = status;
2636
Szymon Janc4e51eae2011-02-25 19:05:48 +01002637 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2638 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002639
Johan Hedberga664b5b2011-02-19 12:06:02 -03002640 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002641
2642 return err;
2643}
Johan Hedberga5c29682011-02-19 12:05:57 -03002644
Brian Gixa68668b2011-08-11 15:49:36 -07002645int mgmt_user_confirm_request(u16 index, u8 event,
2646 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002647{
2648 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002649 struct hci_conn *conn = NULL;
2650 struct hci_dev *hdev;
2651 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2652
2653 BT_DBG("hci%u", index);
2654
2655 hdev = hci_dev_get(index);
2656
Brian Gix64bd5302011-09-08 11:35:48 -07002657 if (!hdev)
2658 return -ENODEV;
2659
Brian Gix64bd5302011-09-08 11:35:48 -07002660 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002661
2662 ev.auto_confirm = 0;
2663
2664 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2665 goto no_auto_confirm;
2666
2667 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2668 rem_cap = conn->remote_cap;
2669 loc_mitm = conn->auth_type & 0x01;
2670 rem_mitm = conn->remote_auth & 0x01;
2671
Brian Gixdbf59292011-11-11 15:45:17 -08002672 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2673 conn->auth_initiator && rem_cap == 0x03)
2674 ev.auto_confirm = 1;
2675 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
Brian Gixa68668b2011-08-11 15:49:36 -07002676 goto no_auto_confirm;
2677
2678
2679 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2680 ev.auto_confirm = 1;
2681
2682no_auto_confirm:
2683 bacpy(&ev.bdaddr, bdaddr);
2684 ev.event = event;
2685 put_unaligned_le32(value, &ev.value);
2686
Brian Gix64bd5302011-09-08 11:35:48 -07002687 hci_dev_put(hdev);
2688
Brian Gixa68668b2011-08-11 15:49:36 -07002689 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2690 NULL);
2691}
2692
2693int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2694{
2695 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002696
2697 BT_DBG("hci%u", index);
2698
Johan Hedberga5c29682011-02-19 12:05:57 -03002699 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002700
Brian Gixa68668b2011-08-11 15:49:36 -07002701 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002702 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002703}
2704
2705static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2706 u8 opcode)
2707{
2708 struct pending_cmd *cmd;
2709 struct mgmt_rp_user_confirm_reply rp;
2710 int err;
2711
2712 cmd = mgmt_pending_find(opcode, index);
2713 if (!cmd)
2714 return -ENOENT;
2715
Johan Hedberga5c29682011-02-19 12:05:57 -03002716 bacpy(&rp.bdaddr, bdaddr);
2717 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002718 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002719
Johan Hedberga664b5b2011-02-19 12:06:02 -03002720 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002721
2722 return err;
2723}
2724
2725int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2726{
2727 return confirm_reply_complete(index, bdaddr, status,
2728 MGMT_OP_USER_CONFIRM_REPLY);
2729}
2730
Szymon Jancb8534e02011-03-01 16:55:34 +01002731int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002732{
2733 return confirm_reply_complete(index, bdaddr, status,
2734 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2735}
Johan Hedberg2a611692011-02-19 12:06:00 -03002736
2737int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2738{
2739 struct mgmt_ev_auth_failed ev;
2740
Johan Hedberg2a611692011-02-19 12:06:00 -03002741 bacpy(&ev.bdaddr, bdaddr);
2742 ev.status = status;
2743
Szymon Janc4e51eae2011-02-25 19:05:48 +01002744 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002745}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002746
2747int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2748{
2749 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002750 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002751 struct mgmt_cp_set_local_name ev;
2752 int err;
2753
2754 memset(&ev, 0, sizeof(ev));
2755 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2756
2757 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2758 if (!cmd)
2759 goto send_event;
2760
2761 if (status) {
2762 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2763 goto failed;
2764 }
2765
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002766 hdev = hci_dev_get(index);
2767 if (hdev) {
2768 hci_dev_lock_bh(hdev);
2769 update_eir(hdev);
2770 hci_dev_unlock_bh(hdev);
2771 hci_dev_put(hdev);
2772 }
2773
Johan Hedbergb312b1612011-03-16 14:29:37 +02002774 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2775 sizeof(ev));
2776 if (err < 0)
2777 goto failed;
2778
2779send_event:
2780 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2781 cmd ? cmd->sk : NULL);
2782
2783failed:
2784 if (cmd)
2785 mgmt_pending_remove(cmd);
2786 return err;
2787}
Szymon Jancc35938b2011-03-22 13:12:21 +01002788
2789int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2790 u8 status)
2791{
2792 struct pending_cmd *cmd;
2793 int err;
2794
2795 BT_DBG("hci%u status %u", index, status);
2796
2797 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2798 if (!cmd)
2799 return -ENOENT;
2800
2801 if (status) {
2802 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2803 EIO);
2804 } else {
2805 struct mgmt_rp_read_local_oob_data rp;
2806
2807 memcpy(rp.hash, hash, sizeof(rp.hash));
2808 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2809
2810 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2811 &rp, sizeof(rp));
2812 }
2813
2814 mgmt_pending_remove(cmd);
2815
2816 return err;
2817}
Johan Hedberge17acd42011-03-30 23:57:16 +03002818
Brian Gixa68668b2011-08-11 15:49:36 -07002819int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2820 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002821{
2822 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002823 struct pending_cmd *cmd;
2824 int err;
2825
2826 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002827
2828 memset(&ev, 0, sizeof(ev));
2829
2830 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002831 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002832 ev.type = type;
2833 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002834
Brian Gixa68668b2011-08-11 15:49:36 -07002835 if (dev_class)
2836 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002837
Brian Gixa68668b2011-08-11 15:49:36 -07002838 if (eir && eir_len)
2839 memcpy(ev.eir, eir, eir_len);
2840
2841 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2842
2843 if (err < 0)
2844 return err;
2845
2846 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2847 if (cmd) {
2848 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002849 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002850
2851 ilp->int_count++;
2852 if (hdev && ilp->int_count >= ilp->int_phase) {
2853 /* Inquiry scan for General Discovery LAP */
2854 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2855 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002856
Brian Gixa68668b2011-08-11 15:49:36 -07002857 ilp->int_phase *= 2;
2858 ilp->int_count = 0;
2859 if (ilp->mode == SCAN_LE) {
2860 /* cancel LE scan */
2861 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2862 sizeof(le_cp), &le_cp);
2863 /* start BR scan */
2864 cp.num_rsp = (u8) ilp->int_phase;
2865 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2866 sizeof(cp), &cp);
2867 ilp->mode = SCAN_BR;
2868 del_timer_sync(&ilp->le_timer);
2869 }
2870 }
Brian Gix64bd5302011-09-08 11:35:48 -07002871
2872 if (hdev)
2873 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002874 }
2875
2876 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002877}
Johan Hedberga88a9652011-03-30 13:18:12 +03002878
Brian Gixa68668b2011-08-11 15:49:36 -07002879
2880int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002881{
2882 struct mgmt_ev_remote_name ev;
2883
2884 memset(&ev, 0, sizeof(ev));
2885
2886 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002887 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002888 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2889
2890 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2891}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302892
2893int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
2894{
2895 struct mgmt_ev_encrypt_change ev;
2896
2897 BT_DBG("hci%u", index);
2898
2899 bacpy(&ev.bdaddr, bdaddr);
2900 ev.status = status;
2901
2902 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
2903 NULL);
2904}
2905