blob: 4a976a9192050976b43de5efa6ef97feb52cfad9 [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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800211 hci_dev_lock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800240 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800380 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800407 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800470 hci_dev_lock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700471
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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800524 hci_dev_unlock_bh(hdev);
Brian Gix8a7f1642011-10-17 17:39:46 -0700525 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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800550 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800585 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800611 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800645 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800706 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800722 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800890 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800914 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800939 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800974 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -0800998 hci_dev_lock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001009 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001031 hci_dev_lock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001049 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001083 hci_dev_lock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001121 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001143 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001166 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001192 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001228 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001249 hci_dev_lock_bh(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);
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001280 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001305 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001327 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001412 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001433 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001456 hci_dev_lock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001463 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001603 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001658 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001688 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001714 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001715 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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001738 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001739
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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001754 hci_dev_unlock_bh(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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001779 hci_dev_lock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001780
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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001796 hci_dev_unlock_bh(hdev);
Brian Gix7f7e16c2011-11-01 16:27:25 -07001797 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
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001820 hci_dev_lock_bh(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:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001835 hci_dev_unlock_bh(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
Brian Gixa68668b2011-08-11 15:49:36 -07001886 if (!hdev || !lmp_le_capable(hdev)) {
1887 struct mgmt_mode cp = {0};
1888
1889 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1890 discovery_terminated, NULL);
1891
1892 mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
Brian Gixa68668b2011-08-11 15:49:36 -07001893
Brian Gix64bd5302011-09-08 11:35:48 -07001894 if (hdev)
1895 goto done;
1896 else
1897 return;
1898 }
Brian Gixa68668b2011-08-11 15:49:36 -07001899
1900 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
1901 if (cmd && cmd->param) {
1902 struct disco_interleave *ilp = cmd->param;
1903
1904 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1905 sizeof(le_cp), &le_cp);
1906 if (err >= 0) {
1907 mod_timer(&ilp->le_timer, jiffies +
1908 msecs_to_jiffies(ilp->int_phase * 1000));
1909 ilp->mode = SCAN_LE;
1910 } else
1911 ilp->mode = SCAN_IDLE;
1912 }
1913
1914 if (err < 0)
1915 mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
1916 discovery_terminated, NULL);
1917
Brian Gix64bd5302011-09-08 11:35:48 -07001918done:
Brian Gixa68668b2011-08-11 15:49:36 -07001919 hci_dev_put(hdev);
1920}
1921
1922static void disco_to(unsigned long data)
1923{
1924 struct disco_interleave *ilp = (void *)data;
1925 struct hci_dev *hdev;
1926 struct pending_cmd *cmd;
1927
1928 BT_DBG("hci%d", ilp->index);
1929
1930 del_timer_sync(&ilp->le_timer);
1931 hdev = hci_dev_get(ilp->index);
1932
1933 if (hdev) {
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001934 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001935
1936 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1937
1938 if (ilp->mode != SCAN_IDLE) {
1939 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1940
1941 if (ilp->mode == SCAN_LE)
1942 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1943 sizeof(le_cp), &le_cp);
1944 else
1945 hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
1946 0, NULL);
1947
1948 ilp->mode = SCAN_IDLE;
1949 }
1950
1951 if (cmd) {
1952 struct mgmt_mode cp = {0};
1953
1954 mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
1955 sizeof(cp), NULL);
1956 mgmt_pending_remove(cmd);
1957 }
1958
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001959 hci_dev_unlock_bh(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001960 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001961 }
1962}
1963
1964static void disco_le_to(unsigned long data)
1965{
1966 struct disco_interleave *ilp = (void *)data;
1967 struct hci_dev *hdev;
1968 struct pending_cmd *cmd;
1969 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
1970
1971 BT_DBG("hci%d", ilp->index);
1972
1973 hdev = hci_dev_get(ilp->index);
Brian Gixa68668b2011-08-11 15:49:36 -07001974
1975 if (hdev) {
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001976 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001977
1978 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
1979
1980 if (ilp->mode == SCAN_LE)
1981 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
1982 sizeof(le_cp), &le_cp);
1983
1984 /* re-start BR scan */
1985 if (cmd) {
1986 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
1987 ilp->int_phase *= 2;
1988 ilp->int_count = 0;
1989 cp.num_rsp = (u8) ilp->int_phase;
1990 hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1991 ilp->mode = SCAN_BR;
1992 } else
1993 ilp->mode = SCAN_IDLE;
1994
Subramanian Srinivasana727a492011-11-30 13:06:07 -08001995 hci_dev_unlock_bh(hdev);
Brian Gix64bd5302011-09-08 11:35:48 -07001996 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07001997 }
1998}
1999
2000static int start_discovery(struct sock *sk, u16 index)
2001{
2002 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 8, 0};
2003 struct hci_dev *hdev;
2004 struct pending_cmd *cmd;
2005 int err;
2006
2007 BT_DBG("");
2008
2009 hdev = hci_dev_get(index);
2010 if (!hdev)
2011 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
2012
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002013 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002014
2015 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
2016 if (!cmd) {
2017 err = -ENOMEM;
2018 goto failed;
2019 }
2020
2021 /* If LE Capable, we will alternate between BR/EDR and LE */
2022 if (lmp_le_capable(hdev)) {
2023 struct hci_cp_le_set_scan_parameters le_cp;
2024
2025 /* Shorten BR scan params */
2026 cp.num_rsp = 1;
2027 cp.length /= 2;
2028
2029 /* Setup LE scan params */
2030 memset(&le_cp, 0, sizeof(le_cp));
2031 le_cp.type = 0x01; /* Active scanning */
2032 /* The recommended value for scan interval and window is
2033 * 11.25 msec. It is calculated by: time = n * 0.625 msec */
2034 le_cp.interval = cpu_to_le16(0x0012);
2035 le_cp.window = cpu_to_le16(0x0012);
2036 le_cp.own_bdaddr_type = 0; /* Public address */
2037 le_cp.filter = 0; /* Accept all adv packets */
2038
2039 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAMETERS,
2040 sizeof(le_cp), &le_cp);
2041 }
2042
2043 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
2044
2045 if (err < 0)
2046 mgmt_pending_remove(cmd);
2047 else if (lmp_le_capable(hdev)) {
2048 struct disco_interleave il, *ilp;
2049
2050 il.int_phase = 1;
2051 il.int_count = 0;
2052 il.index = index;
2053 il.mode = SCAN_BR;
2054 mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
2055 sizeof(struct disco_interleave));
2056 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2057 if (cmd) {
2058 ilp = cmd->param;
2059 setup_timer(&ilp->le_timer, disco_le_to,
2060 (unsigned long) ilp);
2061 setup_timer(&ilp->timer, disco_to, (unsigned long) ilp);
2062 mod_timer(&ilp->timer,
2063 jiffies + msecs_to_jiffies(20000));
2064 }
2065 }
2066
2067failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002068 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002069 hci_dev_put(hdev);
2070
2071 return err;
2072}
2073
2074static int stop_discovery(struct sock *sk, u16 index)
2075{
2076 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
2077 struct mgmt_mode mode_cp = {0};
2078 struct disco_interleave *ilp = NULL;
2079 struct hci_dev *hdev;
2080 struct pending_cmd *cmd = NULL;
2081 int err = -EPERM;
2082
2083 BT_DBG("");
2084
2085 hdev = hci_dev_get(index);
2086 if (!hdev)
2087 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
2088
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002089 hci_dev_lock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002090
2091 if (lmp_le_capable(hdev)) {
2092 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2093 if (!cmd) {
2094 err = -ENOMEM;
2095 goto failed;
2096 }
2097
2098 ilp = cmd->param;
2099 }
2100
2101 if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
2102 err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2103 sizeof(le_cp), &le_cp);
2104
2105 if (err < 0) {
2106 if (!ilp || (ilp->mode == SCAN_BR))
2107 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
2108 0, NULL);
2109 }
2110
2111 if (ilp) {
2112 ilp->mode = SCAN_IDLE;
2113 del_timer_sync(&ilp->le_timer);
2114 del_timer_sync(&ilp->timer);
2115 }
2116
2117 if (err < 0 && cmd)
2118 mgmt_pending_remove(cmd);
2119
2120 mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
2121
2122failed:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002123 hci_dev_unlock_bh(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002124 hci_dev_put(hdev);
2125
2126 if (err < 0)
2127 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, -err);
2128 else
2129 return err;
2130}
2131
Szymon Jancc35938b2011-03-22 13:12:21 +01002132static int read_local_oob_data(struct sock *sk, u16 index)
2133{
2134 struct hci_dev *hdev;
2135 struct pending_cmd *cmd;
2136 int err;
2137
2138 BT_DBG("hci%u", index);
2139
2140 hdev = hci_dev_get(index);
2141 if (!hdev)
2142 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2143 ENODEV);
2144
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002145 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002146
2147 if (!test_bit(HCI_UP, &hdev->flags)) {
2148 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2149 ENETDOWN);
2150 goto unlock;
2151 }
2152
2153 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2154 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2155 EOPNOTSUPP);
2156 goto unlock;
2157 }
2158
2159 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
2160 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
2161 goto unlock;
2162 }
2163
2164 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
2165 if (!cmd) {
2166 err = -ENOMEM;
2167 goto unlock;
2168 }
2169
2170 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2171 if (err < 0)
2172 mgmt_pending_remove(cmd);
2173
2174unlock:
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002175 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002176 hci_dev_put(hdev);
2177
2178 return err;
2179}
2180
Szymon Janc2763eda2011-03-22 13:12:22 +01002181static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
2182 u16 len)
2183{
2184 struct hci_dev *hdev;
2185 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
2186 int err;
2187
2188 BT_DBG("hci%u ", index);
2189
2190 if (len != sizeof(*cp))
2191 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2192 EINVAL);
2193
2194 hdev = hci_dev_get(index);
2195 if (!hdev)
2196 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2197 ENODEV);
2198
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002199 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002200
2201 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
2202 cp->randomizer);
2203 if (err < 0)
2204 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
2205 else
2206 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2207 0);
2208
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002209 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002210 hci_dev_put(hdev);
2211
2212 return err;
2213}
2214
2215static int remove_remote_oob_data(struct sock *sk, u16 index,
2216 unsigned char *data, u16 len)
2217{
2218 struct hci_dev *hdev;
2219 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
2220 int err;
2221
2222 BT_DBG("hci%u ", index);
2223
2224 if (len != sizeof(*cp))
2225 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2226 EINVAL);
2227
2228 hdev = hci_dev_get(index);
2229 if (!hdev)
2230 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2231 ENODEV);
2232
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002233 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002234
2235 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
2236 if (err < 0)
2237 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2238 -err);
2239 else
2240 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2241 NULL, 0);
2242
Subramanian Srinivasana727a492011-11-30 13:06:07 -08002243 hci_dev_unlock_bh(hdev);
Antti Julku58d19802011-06-15 12:01:15 +03002244 hci_dev_put(hdev);
2245
2246 return err;
2247}
2248
Johan Hedberg03811012010-12-08 00:21:06 +02002249int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2250{
2251 unsigned char *buf;
2252 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002253 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002254 int err;
2255
2256 BT_DBG("got %zu bytes", msglen);
2257
2258 if (msglen < sizeof(*hdr))
2259 return -EINVAL;
2260
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002261 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002262 if (!buf)
2263 return -ENOMEM;
2264
2265 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2266 err = -EFAULT;
2267 goto done;
2268 }
2269
2270 hdr = (struct mgmt_hdr *) buf;
2271 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002272 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002273 len = get_unaligned_le16(&hdr->len);
2274
2275 if (len != msglen - sizeof(*hdr)) {
2276 err = -EINVAL;
2277 goto done;
2278 }
2279
Brian Gixa68668b2011-08-11 15:49:36 -07002280 BT_DBG("got opcode %x", opcode);
Johan Hedberg03811012010-12-08 00:21:06 +02002281 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002282 case MGMT_OP_READ_VERSION:
2283 err = read_version(sk);
2284 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002285 case MGMT_OP_READ_INDEX_LIST:
2286 err = read_index_list(sk);
2287 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002288 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002289 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002290 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002291 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002292 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002293 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002294 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002295 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002296 break;
Brian Gix8a7f1642011-10-17 17:39:46 -07002297 case MGMT_OP_SET_LIMIT_DISCOVERABLE:
2298 err = set_limited_discoverable(sk, index, buf + sizeof(*hdr),
2299 len);
2300 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002301 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002302 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002303 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002304 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002305 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002306 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002307 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002308 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002309 break;
2310 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002311 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002312 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002313 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002314 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002315 break;
2316 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002317 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002318 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002319 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002320 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002321 break;
2322 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002323 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002324 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002325 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002326 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002327 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002328 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002329 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002330 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002331 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002332 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002333 break;
2334 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002335 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002336 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002337 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002338 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002339 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002340 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002341 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002342 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002343 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002344 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedberga5c29682011-02-19 12:05:57 -03002345 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gixa68668b2011-08-11 15:49:36 -07002346 err = user_confirm_reply(sk, index, buf + sizeof(*hdr),
2347 len, opcode);
Johan Hedberga5c29682011-02-19 12:05:57 -03002348 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002349 case MGMT_OP_SET_LOCAL_NAME:
2350 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2351 break;
Brian Gixa68668b2011-08-11 15:49:36 -07002352 case MGMT_OP_START_DISCOVERY:
2353 err = start_discovery(sk, index);
2354 break;
2355 case MGMT_OP_STOP_DISCOVERY:
2356 err = stop_discovery(sk, index);
2357 break;
2358 case MGMT_OP_RESOLVE_NAME:
2359 err = resolve_name(sk, index, buf + sizeof(*hdr), len);
2360 break;
Brian Gix7f7e16c2011-11-01 16:27:25 -07002361 case MGMT_OP_SET_CONNECTION_PARAMS:
2362 err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
2363 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002364 case MGMT_OP_READ_LOCAL_OOB_DATA:
2365 err = read_local_oob_data(sk, index);
2366 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002367 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2368 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2369 break;
2370 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2371 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2372 len);
2373 break;
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302374 case MGMT_OP_ENCRYPT_LINK:
2375 err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
2376 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377
Johan Hedberg03811012010-12-08 00:21:06 +02002378 default:
2379 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002380 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02002381 break;
2382 }
2383
Johan Hedberge41d8b42010-12-13 21:07:03 +02002384 if (err < 0)
2385 goto done;
2386
Johan Hedberg03811012010-12-08 00:21:06 +02002387 err = msglen;
2388
2389done:
2390 kfree(buf);
2391 return err;
2392}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002393
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002394int mgmt_index_added(u16 index)
2395{
Brian Gixa68668b2011-08-11 15:49:36 -07002396 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002397 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002398}
2399
2400int mgmt_index_removed(u16 index)
2401{
Brian Gixa68668b2011-08-11 15:49:36 -07002402 BT_DBG("%d", index);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002403 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002404}
2405
Johan Hedberg73f22f62010-12-29 16:00:25 +02002406struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002407 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002408 struct sock *sk;
2409};
2410
Johan Hedberg72a734e2010-12-30 00:38:22 +02002411static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002412{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002413 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002414 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002415
Johan Hedberg72a734e2010-12-30 00:38:22 +02002416 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002417 return;
2418
Johan Hedberg053f0212011-01-26 13:07:10 +02002419 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002420
2421 list_del(&cmd->list);
2422
2423 if (match->sk == NULL) {
2424 match->sk = cmd->sk;
2425 sock_hold(match->sk);
2426 }
2427
2428 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002429}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002430
2431int mgmt_powered(u16 index, u8 powered)
2432{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002433 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002434 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002435 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002436
Brian Gixa68668b2011-08-11 15:49:36 -07002437 BT_DBG("hci%u %d", index, powered);
2438
Johan Hedberg72a734e2010-12-30 00:38:22 +02002439 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002440
Johan Hedberg72a734e2010-12-30 00:38:22 +02002441 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002442
Szymon Janc4e51eae2011-02-25 19:05:48 +01002443 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002444
2445 if (match.sk)
2446 sock_put(match.sk);
2447
2448 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002449}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002450
Johan Hedberg73f22f62010-12-29 16:00:25 +02002451int mgmt_discoverable(u16 index, u8 discoverable)
2452{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002453 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002454 struct cmd_lookup match = { discoverable, NULL };
2455 int ret;
2456
Szymon Jancb8534e02011-03-01 16:55:34 +01002457 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002458
Johan Hedberg72a734e2010-12-30 00:38:22 +02002459 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002460
Szymon Janc4e51eae2011-02-25 19:05:48 +01002461 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2462 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002463
2464 if (match.sk)
2465 sock_put(match.sk);
2466
2467 return ret;
2468}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002469
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002470int mgmt_connectable(u16 index, u8 connectable)
2471{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002472 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002473 struct cmd_lookup match = { connectable, NULL };
2474 int ret;
2475
Johan Hedberg72a734e2010-12-30 00:38:22 +02002476 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002477
Johan Hedberg72a734e2010-12-30 00:38:22 +02002478 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002479
Szymon Janc4e51eae2011-02-25 19:05:48 +01002480 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002481
2482 if (match.sk)
2483 sock_put(match.sk);
2484
2485 return ret;
2486}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002487
Brian Gixa68668b2011-08-11 15:49:36 -07002488int mgmt_new_key(u16 index, struct link_key *key, u8 bonded)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002489{
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002490 struct mgmt_ev_new_key *ev;
2491 int err, total;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002492
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002493 total = sizeof(struct mgmt_ev_new_key) + key->dlen;
2494 ev = kzalloc(total, GFP_ATOMIC);
2495 if (!ev)
2496 return -ENOMEM;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002497
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002498 bacpy(&ev->key.bdaddr, &key->bdaddr);
Brian Gixcf956772011-10-20 15:18:51 -07002499 ev->key.addr_type = key->addr_type;
2500 ev->key.key_type = key->key_type;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002501 memcpy(ev->key.val, key->val, 16);
2502 ev->key.pin_len = key->pin_len;
Brian Gixa68668b2011-08-11 15:49:36 -07002503 ev->key.auth = key->auth;
2504 ev->store_hint = bonded;
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002505 ev->key.dlen = key->dlen;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002506
Vinicius Costa Gomesc00ddbf2011-07-08 18:31:44 -03002507 memcpy(ev->key.data, key->data, key->dlen);
2508
2509 err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
2510
2511 kfree(ev);
2512
2513 return err;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002514}
Johan Hedbergf7520542011-01-20 12:34:39 +02002515
Brian Gix2e2f50d2011-09-13 12:36:04 -07002516int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
Johan Hedbergf7520542011-01-20 12:34:39 +02002517{
2518 struct mgmt_ev_connected ev;
2519
Johan Hedbergf7520542011-01-20 12:34:39 +02002520 bacpy(&ev.bdaddr, bdaddr);
Brian Gix2e2f50d2011-09-13 12:36:04 -07002521 ev.le = le;
Johan Hedbergf7520542011-01-20 12:34:39 +02002522
Szymon Janc4e51eae2011-02-25 19:05:48 +01002523 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002524}
2525
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2527{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002528 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002529 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002530 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531
Johan Hedberga38528f2011-01-22 06:46:43 +02002532 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002533
Szymon Janc4e51eae2011-02-25 19:05:48 +01002534 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002535
2536 *sk = cmd->sk;
2537 sock_hold(*sk);
2538
Johan Hedberga664b5b2011-02-19 12:06:02 -03002539 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002540}
2541
Johan Hedbergf7520542011-01-20 12:34:39 +02002542int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2543{
2544 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002545 struct sock *sk = NULL;
2546 int err;
2547
2548 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002549
Johan Hedbergf7520542011-01-20 12:34:39 +02002550 bacpy(&ev.bdaddr, bdaddr);
2551
Szymon Janc4e51eae2011-02-25 19:05:48 +01002552 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002553
2554 if (sk)
2555 sock_put(sk);
2556
2557 return err;
2558}
2559
2560int mgmt_disconnect_failed(u16 index)
2561{
2562 struct pending_cmd *cmd;
2563 int err;
2564
2565 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2566 if (!cmd)
2567 return -ENOENT;
2568
Szymon Janc4e51eae2011-02-25 19:05:48 +01002569 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002570
Johan Hedberga664b5b2011-02-19 12:06:02 -03002571 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002572
2573 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002574}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002575
2576int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2577{
2578 struct mgmt_ev_connect_failed ev;
2579
Johan Hedberg17d5c042011-01-22 06:09:08 +02002580 bacpy(&ev.bdaddr, bdaddr);
2581 ev.status = status;
2582
Szymon Janc4e51eae2011-02-25 19:05:48 +01002583 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002584}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002587{
2588 struct mgmt_ev_pin_code_request ev;
2589
Brian Gixa68668b2011-08-11 15:49:36 -07002590 BT_DBG("hci%u", index);
2591
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002593 ev.secure = 0;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002594
Szymon Janc4e51eae2011-02-25 19:05:48 +01002595 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2596 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002597}
2598
2599int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2600{
2601 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002602 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002603 int err;
2604
2605 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2606 if (!cmd)
2607 return -ENOENT;
2608
Johan Hedbergac56fb12011-02-19 12:05:59 -03002609 bacpy(&rp.bdaddr, bdaddr);
2610 rp.status = status;
2611
Szymon Janc4e51eae2011-02-25 19:05:48 +01002612 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2613 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002614
Johan Hedberga664b5b2011-02-19 12:06:02 -03002615 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002616
2617 return err;
2618}
2619
2620int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2621{
2622 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002623 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002624 int err;
2625
2626 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2627 if (!cmd)
2628 return -ENOENT;
2629
Johan Hedbergac56fb12011-02-19 12:05:59 -03002630 bacpy(&rp.bdaddr, bdaddr);
2631 rp.status = status;
2632
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2634 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002635
Johan Hedberga664b5b2011-02-19 12:06:02 -03002636 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002637
2638 return err;
2639}
Johan Hedberga5c29682011-02-19 12:05:57 -03002640
Brian Gixa68668b2011-08-11 15:49:36 -07002641int mgmt_user_confirm_request(u16 index, u8 event,
2642 bdaddr_t *bdaddr, __le32 value)
Johan Hedberga5c29682011-02-19 12:05:57 -03002643{
2644 struct mgmt_ev_user_confirm_request ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002645 struct hci_conn *conn = NULL;
2646 struct hci_dev *hdev;
2647 u8 loc_cap, rem_cap, loc_mitm, rem_mitm;
2648
2649 BT_DBG("hci%u", index);
2650
2651 hdev = hci_dev_get(index);
2652
Brian Gix64bd5302011-09-08 11:35:48 -07002653 if (!hdev)
2654 return -ENODEV;
2655
Brian Gix64bd5302011-09-08 11:35:48 -07002656 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002657
2658 ev.auto_confirm = 0;
2659
2660 if (!conn || event != HCI_EV_USER_CONFIRM_REQUEST)
2661 goto no_auto_confirm;
2662
2663 loc_cap = (conn->io_capability == 0x04) ? 0x01 : conn->io_capability;
2664 rem_cap = conn->remote_cap;
2665 loc_mitm = conn->auth_type & 0x01;
2666 rem_mitm = conn->remote_auth & 0x01;
2667
Brian Gixdbf59292011-11-11 15:45:17 -08002668 if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
2669 conn->auth_initiator && rem_cap == 0x03)
2670 ev.auto_confirm = 1;
2671 else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
Brian Gixa68668b2011-08-11 15:49:36 -07002672 goto no_auto_confirm;
2673
2674
2675 if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
2676 ev.auto_confirm = 1;
2677
2678no_auto_confirm:
2679 bacpy(&ev.bdaddr, bdaddr);
2680 ev.event = event;
2681 put_unaligned_le32(value, &ev.value);
2682
Brian Gix64bd5302011-09-08 11:35:48 -07002683 hci_dev_put(hdev);
2684
Brian Gixa68668b2011-08-11 15:49:36 -07002685 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2686 NULL);
2687}
2688
2689int mgmt_user_passkey_request(u16 index, bdaddr_t *bdaddr)
2690{
2691 struct mgmt_ev_user_passkey_request ev;
Johan Hedberga5c29682011-02-19 12:05:57 -03002692
2693 BT_DBG("hci%u", index);
2694
Johan Hedberga5c29682011-02-19 12:05:57 -03002695 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberga5c29682011-02-19 12:05:57 -03002696
Brian Gixa68668b2011-08-11 15:49:36 -07002697 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, index, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002698 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002699}
2700
2701static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2702 u8 opcode)
2703{
2704 struct pending_cmd *cmd;
2705 struct mgmt_rp_user_confirm_reply rp;
2706 int err;
2707
2708 cmd = mgmt_pending_find(opcode, index);
2709 if (!cmd)
2710 return -ENOENT;
2711
Johan Hedberga5c29682011-02-19 12:05:57 -03002712 bacpy(&rp.bdaddr, bdaddr);
2713 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002714 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002715
Johan Hedberga664b5b2011-02-19 12:06:02 -03002716 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002717
2718 return err;
2719}
2720
2721int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2722{
2723 return confirm_reply_complete(index, bdaddr, status,
2724 MGMT_OP_USER_CONFIRM_REPLY);
2725}
2726
Szymon Jancb8534e02011-03-01 16:55:34 +01002727int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002728{
2729 return confirm_reply_complete(index, bdaddr, status,
2730 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2731}
Johan Hedberg2a611692011-02-19 12:06:00 -03002732
2733int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2734{
2735 struct mgmt_ev_auth_failed ev;
2736
Johan Hedberg2a611692011-02-19 12:06:00 -03002737 bacpy(&ev.bdaddr, bdaddr);
2738 ev.status = status;
2739
Szymon Janc4e51eae2011-02-25 19:05:48 +01002740 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002741}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002742
2743int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2744{
2745 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002746 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002747 struct mgmt_cp_set_local_name ev;
2748 int err;
2749
2750 memset(&ev, 0, sizeof(ev));
2751 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2752
2753 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2754 if (!cmd)
2755 goto send_event;
2756
2757 if (status) {
2758 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2759 goto failed;
2760 }
2761
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002762 hdev = hci_dev_get(index);
2763 if (hdev) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002764 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002765 hci_dev_put(hdev);
2766 }
2767
Johan Hedbergb312b1612011-03-16 14:29:37 +02002768 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2769 sizeof(ev));
2770 if (err < 0)
2771 goto failed;
2772
2773send_event:
2774 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2775 cmd ? cmd->sk : NULL);
2776
2777failed:
2778 if (cmd)
2779 mgmt_pending_remove(cmd);
2780 return err;
2781}
Szymon Jancc35938b2011-03-22 13:12:21 +01002782
2783int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2784 u8 status)
2785{
2786 struct pending_cmd *cmd;
2787 int err;
2788
2789 BT_DBG("hci%u status %u", index, status);
2790
2791 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2792 if (!cmd)
2793 return -ENOENT;
2794
2795 if (status) {
2796 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2797 EIO);
2798 } else {
2799 struct mgmt_rp_read_local_oob_data rp;
2800
2801 memcpy(rp.hash, hash, sizeof(rp.hash));
2802 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2803
2804 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2805 &rp, sizeof(rp));
2806 }
2807
2808 mgmt_pending_remove(cmd);
2809
2810 return err;
2811}
Johan Hedberge17acd42011-03-30 23:57:16 +03002812
Brian Gixa68668b2011-08-11 15:49:36 -07002813int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le,
2814 u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002815{
2816 struct mgmt_ev_device_found ev;
Brian Gixa68668b2011-08-11 15:49:36 -07002817 struct pending_cmd *cmd;
2818 int err;
2819
2820 BT_DBG("le: %d", le);
Johan Hedberge17acd42011-03-30 23:57:16 +03002821
2822 memset(&ev, 0, sizeof(ev));
2823
2824 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002825 ev.rssi = rssi;
Brian Gixa68668b2011-08-11 15:49:36 -07002826 ev.type = type;
2827 ev.le = le;
Johan Hedberge17acd42011-03-30 23:57:16 +03002828
Brian Gixa68668b2011-08-11 15:49:36 -07002829 if (dev_class)
2830 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
Johan Hedberge17acd42011-03-30 23:57:16 +03002831
Brian Gixa68668b2011-08-11 15:49:36 -07002832 if (eir && eir_len)
2833 memcpy(ev.eir, eir, eir_len);
2834
2835 err = mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2836
2837 if (err < 0)
2838 return err;
2839
2840 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2841 if (cmd) {
2842 struct disco_interleave *ilp = cmd->param;
Brian Gix64bd5302011-09-08 11:35:48 -07002843 struct hci_dev *hdev = hci_dev_get(index);
Brian Gixa68668b2011-08-11 15:49:36 -07002844
2845 ilp->int_count++;
2846 if (hdev && ilp->int_count >= ilp->int_phase) {
2847 /* Inquiry scan for General Discovery LAP */
2848 struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
2849 struct hci_cp_le_set_scan_enable le_cp = {0, 0};
Brian Gix64bd5302011-09-08 11:35:48 -07002850
Brian Gixa68668b2011-08-11 15:49:36 -07002851 ilp->int_phase *= 2;
2852 ilp->int_count = 0;
2853 if (ilp->mode == SCAN_LE) {
2854 /* cancel LE scan */
2855 hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
2856 sizeof(le_cp), &le_cp);
2857 /* start BR scan */
2858 cp.num_rsp = (u8) ilp->int_phase;
2859 hci_send_cmd(hdev, HCI_OP_INQUIRY,
2860 sizeof(cp), &cp);
2861 ilp->mode = SCAN_BR;
2862 del_timer_sync(&ilp->le_timer);
2863 }
2864 }
Brian Gix64bd5302011-09-08 11:35:48 -07002865
2866 if (hdev)
2867 hci_dev_put(hdev);
Brian Gixa68668b2011-08-11 15:49:36 -07002868 }
2869
2870 return 0;
Johan Hedberge17acd42011-03-30 23:57:16 +03002871}
Johan Hedberga88a9652011-03-30 13:18:12 +03002872
Brian Gixa68668b2011-08-11 15:49:36 -07002873
2874int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002875{
2876 struct mgmt_ev_remote_name ev;
2877
2878 memset(&ev, 0, sizeof(ev));
2879
2880 bacpy(&ev.bdaddr, bdaddr);
Brian Gixa68668b2011-08-11 15:49:36 -07002881 ev.status = status;
Johan Hedberga88a9652011-03-30 13:18:12 +03002882 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2883
2884 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2885}
Prabhakaran Mc46230fa2011-11-30 18:11:21 +05302886
2887int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status)
2888{
2889 struct mgmt_ev_encrypt_change ev;
2890
2891 BT_DBG("hci%u", index);
2892
2893 bacpy(&ev.bdaddr, bdaddr);
2894 ev.status = status;
2895
2896 return mgmt_event(MGMT_EV_ENCRYPT_CHANGE, index, &ev, sizeof(ev),
2897 NULL);
2898}
2899