blob: 4476d8e3c0f2e5942830e34b6772ed5609ff3afe [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>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
44LIST_HEAD(cmd_list);
45
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
Szymon Janc34eb5252011-02-28 14:10:08 +010052 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020053
54 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
55 if (!skb)
56 return -ENOMEM;
57
58 hdr = (void *) skb_put(skb, sizeof(*hdr));
59
60 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010061 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020062 hdr->len = cpu_to_le16(sizeof(*ev));
63
64 ev = (void *) skb_put(skb, sizeof(*ev));
65 ev->status = status;
66 put_unaligned_le16(cmd, &ev->opcode);
67
68 if (sock_queue_rcv_skb(sk, skb) < 0)
69 kfree_skb(skb);
70
71 return 0;
72}
73
Szymon Janc4e51eae2011-02-25 19:05:48 +010074static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
75 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020076{
77 struct sk_buff *skb;
78 struct mgmt_hdr *hdr;
79 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020080
81 BT_DBG("sock %p", sk);
82
Johan Hedberga38528f2011-01-22 06:46:43 +020083 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020084 if (!skb)
85 return -ENOMEM;
86
87 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020088
Johan Hedberg02d98122010-12-13 21:07:04 +020089 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010090 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020091 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020092
Johan Hedberga38528f2011-01-22 06:46:43 +020093 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
94 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010095
96 if (rp)
97 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020098
99 if (sock_queue_rcv_skb(sk, skb) < 0)
100 kfree_skb(skb);
101
102 return 0;
103}
104
Johan Hedberga38528f2011-01-22 06:46:43 +0200105static int read_version(struct sock *sk)
106{
107 struct mgmt_rp_read_version rp;
108
109 BT_DBG("sock %p", sk);
110
111 rp.version = MGMT_VERSION;
112 put_unaligned_le16(MGMT_REVISION, &rp.revision);
113
Szymon Janc4e51eae2011-02-25 19:05:48 +0100114 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
115 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200116}
117
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200118static int read_index_list(struct sock *sk)
119{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200120 struct mgmt_rp_read_index_list *rp;
121 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200122 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200123 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200124 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200125
126 BT_DBG("sock %p", sk);
127
128 read_lock(&hci_dev_list_lock);
129
130 count = 0;
131 list_for_each(p, &hci_dev_list) {
132 count++;
133 }
134
Johan Hedberga38528f2011-01-22 06:46:43 +0200135 rp_len = sizeof(*rp) + (2 * count);
136 rp = kmalloc(rp_len, GFP_ATOMIC);
137 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100138 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100140 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200141
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142 put_unaligned_le16(count, &rp->num_controllers);
143
144 i = 0;
145 list_for_each(p, &hci_dev_list) {
146 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200147
148 hci_del_off_timer(d);
149
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200150 set_bit(HCI_MGMT, &d->flags);
151
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200152 if (test_bit(HCI_SETUP, &d->flags))
153 continue;
154
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200155 put_unaligned_le16(d->id, &rp->index[i++]);
156 BT_DBG("Added hci%u", d->id);
157 }
158
159 read_unlock(&hci_dev_list_lock);
160
Szymon Janc4e51eae2011-02-25 19:05:48 +0100161 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
162 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200163
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 kfree(rp);
165
166 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200167}
168
Szymon Janc4e51eae2011-02-25 19:05:48 +0100169static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200170{
Johan Hedberga38528f2011-01-22 06:46:43 +0200171 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200172 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200173
Szymon Janc4e51eae2011-02-25 19:05:48 +0100174 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200175
Szymon Janc4e51eae2011-02-25 19:05:48 +0100176 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200177 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200179
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200180 hci_del_off_timer(hdev);
181
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200182 hci_dev_lock_bh(hdev);
183
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200184 set_bit(HCI_MGMT, &hdev->flags);
185
Johan Hedberga38528f2011-01-22 06:46:43 +0200186 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 rp.powered = test_bit(HCI_UP, &hdev->flags);
189 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
190 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
191 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200192
193 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200194 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 bacpy(&rp.bdaddr, &hdev->bdaddr);
201 memcpy(rp.features, hdev->features, 8);
202 memcpy(rp.dev_class, hdev->dev_class, 3);
203 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
204 rp.hci_ver = hdev->hci_ver;
205 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206
207 hci_dev_unlock_bh(hdev);
208 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200209
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200211}
212
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200213static void mgmt_pending_free(struct pending_cmd *cmd)
214{
215 sock_put(cmd->sk);
216 kfree(cmd->cmd);
217 kfree(cmd);
218}
219
Johan Hedberg366a0332011-02-19 12:05:55 -0300220static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
221 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200222{
223 struct pending_cmd *cmd;
224
225 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
226 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300227 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200228
229 cmd->opcode = opcode;
230 cmd->index = index;
231
232 cmd->cmd = kmalloc(len, GFP_ATOMIC);
233 if (!cmd->cmd) {
234 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300235 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200236 }
237
238 memcpy(cmd->cmd, data, len);
239
240 cmd->sk = sk;
241 sock_hold(sk);
242
243 list_add(&cmd->list, &cmd_list);
244
Johan Hedberg366a0332011-02-19 12:05:55 -0300245 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200246}
247
248static void mgmt_pending_foreach(u16 opcode, int index,
249 void (*cb)(struct pending_cmd *cmd, void *data),
250 void *data)
251{
252 struct list_head *p, *n;
253
254 list_for_each_safe(p, n, &cmd_list) {
255 struct pending_cmd *cmd;
256
257 cmd = list_entry(p, struct pending_cmd, list);
258
259 if (cmd->opcode != opcode)
260 continue;
261
262 if (index >= 0 && cmd->index != index)
263 continue;
264
265 cb(cmd, data);
266 }
267}
268
269static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
270{
271 struct list_head *p;
272
273 list_for_each(p, &cmd_list) {
274 struct pending_cmd *cmd;
275
276 cmd = list_entry(p, struct pending_cmd, list);
277
278 if (cmd->opcode != opcode)
279 continue;
280
281 if (index >= 0 && cmd->index != index)
282 continue;
283
284 return cmd;
285 }
286
287 return NULL;
288}
289
Johan Hedberga664b5b2011-02-19 12:06:02 -0300290static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200291{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200292 list_del(&cmd->list);
293 mgmt_pending_free(cmd);
294}
295
Szymon Janc4e51eae2011-02-25 19:05:48 +0100296static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200297{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200298 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300300 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300301 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302
303 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304
Szymon Janc4e51eae2011-02-25 19:05:48 +0100305 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100307 if (len != sizeof(*cp))
308 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
309
Szymon Janc4e51eae2011-02-25 19:05:48 +0100310 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100312 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200313
314 hci_dev_lock_bh(hdev);
315
316 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200317 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100318 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319 goto failed;
320 }
321
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 goto failed;
325 }
326
Szymon Janc4e51eae2011-02-25 19:05:48 +0100327 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300328 if (!cmd) {
329 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300331 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332
Johan Hedberg72a734e2010-12-30 00:38:22 +0200333 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 queue_work(hdev->workqueue, &hdev->power_on);
335 else
336 queue_work(hdev->workqueue, &hdev->power_off);
337
Johan Hedberg366a0332011-02-19 12:05:55 -0300338 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339
340failed:
341 hci_dev_unlock_bh(hdev);
342 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300343 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344}
345
Szymon Janc4e51eae2011-02-25 19:05:48 +0100346static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
347 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200348{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200349 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200350 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300351 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352 u8 scan;
353 int err;
354
355 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356
Szymon Janc4e51eae2011-02-25 19:05:48 +0100357 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100359 if (len != sizeof(*cp))
360 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100364 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200365
366 hci_dev_lock_bh(hdev);
367
368 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200370 goto failed;
371 }
372
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
374 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
375 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 goto failed;
377 }
378
Johan Hedberg72a734e2010-12-30 00:38:22 +0200379 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100381 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 goto failed;
383 }
384
Szymon Janc4e51eae2011-02-25 19:05:48 +0100385 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300386 if (!cmd) {
387 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300389 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200390
391 scan = SCAN_PAGE;
392
Johan Hedberg72a734e2010-12-30 00:38:22 +0200393 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 scan |= SCAN_INQUIRY;
395
396 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
397 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300398 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399
400failed:
401 hci_dev_unlock_bh(hdev);
402 hci_dev_put(hdev);
403
404 return err;
405}
406
Szymon Janc4e51eae2011-02-25 19:05:48 +0100407static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
408 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200409{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200410 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300412 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413 u8 scan;
414 int err;
415
416 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417
Szymon Janc4e51eae2011-02-25 19:05:48 +0100418 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100420 if (len != sizeof(*cp))
421 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100425 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426
427 hci_dev_lock_bh(hdev);
428
429 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431 goto failed;
432 }
433
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
435 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
436 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437 goto failed;
438 }
439
Johan Hedberg72a734e2010-12-30 00:38:22 +0200440 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300446 if (!cmd) {
447 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300449 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450
Johan Hedberg72a734e2010-12-30 00:38:22 +0200451 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 scan = SCAN_PAGE;
453 else
454 scan = 0;
455
456 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
457 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300458 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459
460failed:
461 hci_dev_unlock_bh(hdev);
462 hci_dev_put(hdev);
463
464 return err;
465}
466
Szymon Janc4e51eae2011-02-25 19:05:48 +0100467static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
468 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200469{
470 struct sk_buff *skb;
471 struct mgmt_hdr *hdr;
472
473 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
474 if (!skb)
475 return -ENOMEM;
476
477 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
478
479 hdr = (void *) skb_put(skb, sizeof(*hdr));
480 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100481 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200482 hdr->len = cpu_to_le16(data_len);
483
Szymon Janc4e51eae2011-02-25 19:05:48 +0100484 if (data)
485 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200486
487 hci_send_to_sock(NULL, skb, skip_sk);
488 kfree_skb(skb);
489
490 return 0;
491}
492
Johan Hedberg053f0212011-01-26 13:07:10 +0200493static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
494{
Johan Hedberga38528f2011-01-22 06:46:43 +0200495 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200496
Johan Hedberga38528f2011-01-22 06:46:43 +0200497 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200498
Szymon Janc4e51eae2011-02-25 19:05:48 +0100499 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200500}
501
Szymon Janc4e51eae2011-02-25 19:05:48 +0100502static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
503 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200504{
505 struct mgmt_mode *cp, ev;
506 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200507 int err;
508
509 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200510
Szymon Janc4e51eae2011-02-25 19:05:48 +0100511 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200512
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100513 if (len != sizeof(*cp))
514 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100518 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200519
520 hci_dev_lock_bh(hdev);
521
522 if (cp->val)
523 set_bit(HCI_PAIRABLE, &hdev->flags);
524 else
525 clear_bit(HCI_PAIRABLE, &hdev->flags);
526
Szymon Janc4e51eae2011-02-25 19:05:48 +0100527 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528 if (err < 0)
529 goto failed;
530
Johan Hedbergc542a062011-01-26 13:11:03 +0200531 ev.val = cp->val;
532
Szymon Janc4e51eae2011-02-25 19:05:48 +0100533 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200534
535failed:
536 hci_dev_unlock_bh(hdev);
537 hci_dev_put(hdev);
538
539 return err;
540}
541
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200542static u8 get_service_classes(struct hci_dev *hdev)
543{
544 struct list_head *p;
545 u8 val = 0;
546
547 list_for_each(p, &hdev->uuids) {
548 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
549
550 val |= uuid->svc_hint;
551 }
552
553 return val;
554}
555
556static int update_class(struct hci_dev *hdev)
557{
558 u8 cod[3];
559
560 BT_DBG("%s", hdev->name);
561
562 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
563 return 0;
564
565 cod[0] = hdev->minor_class;
566 cod[1] = hdev->major_class;
567 cod[2] = get_service_classes(hdev);
568
569 if (memcmp(cod, hdev->dev_class, 3) == 0)
570 return 0;
571
572 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
573}
574
Szymon Janc4e51eae2011-02-25 19:05:48 +0100575static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200576{
577 struct mgmt_cp_add_uuid *cp;
578 struct hci_dev *hdev;
579 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200580 int err;
581
582 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200583
Szymon Janc4e51eae2011-02-25 19:05:48 +0100584 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200585
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100586 if (len != sizeof(*cp))
587 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
588
Szymon Janc4e51eae2011-02-25 19:05:48 +0100589 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200590 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100591 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200592
593 hci_dev_lock_bh(hdev);
594
595 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
596 if (!uuid) {
597 err = -ENOMEM;
598 goto failed;
599 }
600
601 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200602 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200603
604 list_add(&uuid->list, &hdev->uuids);
605
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200606 err = update_class(hdev);
607 if (err < 0)
608 goto failed;
609
Szymon Janc4e51eae2011-02-25 19:05:48 +0100610 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200611
612failed:
613 hci_dev_unlock_bh(hdev);
614 hci_dev_put(hdev);
615
616 return err;
617}
618
Szymon Janc4e51eae2011-02-25 19:05:48 +0100619static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200620{
621 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100622 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200623 struct hci_dev *hdev;
624 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 +0200625 int err, found;
626
627 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200628
Szymon Janc4e51eae2011-02-25 19:05:48 +0100629 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200630
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100631 if (len != sizeof(*cp))
632 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
633
Szymon Janc4e51eae2011-02-25 19:05:48 +0100634 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200635 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100636 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200637
638 hci_dev_lock_bh(hdev);
639
640 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
641 err = hci_uuids_clear(hdev);
642 goto unlock;
643 }
644
645 found = 0;
646
647 list_for_each_safe(p, n, &hdev->uuids) {
648 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
649
650 if (memcmp(match->uuid, cp->uuid, 16) != 0)
651 continue;
652
653 list_del(&match->list);
654 found++;
655 }
656
657 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100658 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200659 goto unlock;
660 }
661
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200662 err = update_class(hdev);
663 if (err < 0)
664 goto unlock;
665
Szymon Janc4e51eae2011-02-25 19:05:48 +0100666 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200667
668unlock:
669 hci_dev_unlock_bh(hdev);
670 hci_dev_put(hdev);
671
672 return err;
673}
674
Szymon Janc4e51eae2011-02-25 19:05:48 +0100675static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
676 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200677{
678 struct hci_dev *hdev;
679 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200680 int err;
681
682 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200683
Szymon Janc4e51eae2011-02-25 19:05:48 +0100684 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200685
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100686 if (len != sizeof(*cp))
687 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
688
Szymon Janc4e51eae2011-02-25 19:05:48 +0100689 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100691 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200692
693 hci_dev_lock_bh(hdev);
694
695 hdev->major_class = cp->major;
696 hdev->minor_class = cp->minor;
697
698 err = update_class(hdev);
699
700 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100701 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702
703 hci_dev_unlock_bh(hdev);
704 hci_dev_put(hdev);
705
706 return err;
707}
708
Szymon Janc4e51eae2011-02-25 19:05:48 +0100709static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
710 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200711{
712 struct hci_dev *hdev;
713 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200714 int err;
715
716 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200717
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100718 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100719 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100720
Szymon Janc4e51eae2011-02-25 19:05:48 +0100721 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200722 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100723 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200724
725 hci_dev_lock_bh(hdev);
726
Szymon Janc4e51eae2011-02-25 19:05:48 +0100727 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200728
729 if (cp->enable) {
730 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
731 err = 0;
732 } else {
733 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
734 err = update_class(hdev);
735 }
736
737 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
739 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200740
741 hci_dev_unlock_bh(hdev);
742 hci_dev_put(hdev);
743
744 return err;
745}
746
Szymon Janc4e51eae2011-02-25 19:05:48 +0100747static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200748{
749 struct hci_dev *hdev;
750 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100751 u16 key_count, expected_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200752 int i;
753
754 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100755
756 if (len < sizeof(*cp))
757 return -EINVAL;
758
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200759 key_count = get_unaligned_le16(&cp->key_count);
760
761 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
762 if (expected_len != len) {
763 BT_ERR("load_keys: expected %u bytes, got %u bytes",
764 len, expected_len);
765 return -EINVAL;
766 }
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200769 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100770 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200771
Szymon Janc4e51eae2011-02-25 19:05:48 +0100772 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200773 key_count);
774
775 hci_dev_lock_bh(hdev);
776
777 hci_link_keys_clear(hdev);
778
779 set_bit(HCI_LINK_KEYS, &hdev->flags);
780
781 if (cp->debug_keys)
782 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
783 else
784 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
785
786 for (i = 0; i < key_count; i++) {
787 struct mgmt_key_info *key = &cp->keys[i];
788
789 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
790 key->pin_len);
791 }
792
793 hci_dev_unlock_bh(hdev);
794 hci_dev_put(hdev);
795
796 return 0;
797}
798
Szymon Janc4e51eae2011-02-25 19:05:48 +0100799static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200800{
801 struct hci_dev *hdev;
802 struct mgmt_cp_remove_key *cp;
803 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200804 int err;
805
806 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200807
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100808 if (len != sizeof(*cp))
809 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
810
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200812 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100813 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200814
815 hci_dev_lock_bh(hdev);
816
817 err = hci_remove_link_key(hdev, &cp->bdaddr);
818 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200820 goto unlock;
821 }
822
823 err = 0;
824
825 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
826 goto unlock;
827
828 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
829 if (conn) {
830 struct hci_cp_disconnect dc;
831
832 put_unaligned_le16(conn->handle, &dc.handle);
833 dc.reason = 0x13; /* Remote User Terminated Connection */
834 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
835 }
836
837unlock:
838 hci_dev_unlock_bh(hdev);
839 hci_dev_put(hdev);
840
841 return err;
842}
843
Szymon Janc4e51eae2011-02-25 19:05:48 +0100844static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200845{
846 struct hci_dev *hdev;
847 struct mgmt_cp_disconnect *cp;
848 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300849 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200850 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200851 int err;
852
853 BT_DBG("");
854
855 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200856
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100857 if (len != sizeof(*cp))
858 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
859
Szymon Janc4e51eae2011-02-25 19:05:48 +0100860 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200861 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200863
864 hci_dev_lock_bh(hdev);
865
866 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100867 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200868 goto failed;
869 }
870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
872 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200873 goto failed;
874 }
875
876 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
877 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200879 goto failed;
880 }
881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300883 if (!cmd) {
884 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200885 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300886 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200887
888 put_unaligned_le16(conn->handle, &dc.handle);
889 dc.reason = 0x13; /* Remote User Terminated Connection */
890
891 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
892 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300893 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200894
895failed:
896 hci_dev_unlock_bh(hdev);
897 hci_dev_put(hdev);
898
899 return err;
900}
901
Szymon Janc8ce62842011-03-01 16:55:32 +0100902static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200903{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200904 struct mgmt_rp_get_connections *rp;
905 struct hci_dev *hdev;
906 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200907 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100908 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200909 int i, err;
910
911 BT_DBG("");
912
Szymon Janc4e51eae2011-02-25 19:05:48 +0100913 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200914 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100915 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200916
917 hci_dev_lock_bh(hdev);
918
919 count = 0;
920 list_for_each(p, &hdev->conn_hash.list) {
921 count++;
922 }
923
Johan Hedberga38528f2011-01-22 06:46:43 +0200924 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
925 rp = kmalloc(rp_len, GFP_ATOMIC);
926 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200927 err = -ENOMEM;
928 goto unlock;
929 }
930
Johan Hedberg2784eb42011-01-21 13:56:35 +0200931 put_unaligned_le16(count, &rp->conn_count);
932
933 read_lock(&hci_dev_list_lock);
934
935 i = 0;
936 list_for_each(p, &hdev->conn_hash.list) {
937 struct hci_conn *c = list_entry(p, struct hci_conn, list);
938
939 bacpy(&rp->conn[i++], &c->dst);
940 }
941
942 read_unlock(&hci_dev_list_lock);
943
Szymon Janc4e51eae2011-02-25 19:05:48 +0100944 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200945
946unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200947 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200948 hci_dev_unlock_bh(hdev);
949 hci_dev_put(hdev);
950 return err;
951}
952
Szymon Janc4e51eae2011-02-25 19:05:48 +0100953static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
954 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200955{
956 struct hci_dev *hdev;
957 struct mgmt_cp_pin_code_reply *cp;
958 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300959 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200960 int err;
961
962 BT_DBG("");
963
964 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200965
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100966 if (len != sizeof(*cp))
967 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
968
Szymon Janc4e51eae2011-02-25 19:05:48 +0100969 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200970 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200972
973 hci_dev_lock_bh(hdev);
974
975 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200977 goto failed;
978 }
979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300981 if (!cmd) {
982 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200983 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300984 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200985
986 bacpy(&reply.bdaddr, &cp->bdaddr);
987 reply.pin_len = cp->pin_len;
988 memcpy(reply.pin_code, cp->pin_code, 16);
989
990 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
991 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300992 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200993
994failed:
995 hci_dev_unlock_bh(hdev);
996 hci_dev_put(hdev);
997
998 return err;
999}
1000
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1002 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001003{
1004 struct hci_dev *hdev;
1005 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001006 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001007 int err;
1008
1009 BT_DBG("");
1010
1011 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001012
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001013 if (len != sizeof(*cp))
1014 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1015 EINVAL);
1016
Szymon Janc4e51eae2011-02-25 19:05:48 +01001017 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001018 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001019 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1020 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001021
1022 hci_dev_lock_bh(hdev);
1023
1024 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1026 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001027 goto failed;
1028 }
1029
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001031 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001032 if (!cmd) {
1033 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001034 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001035 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001036
Szymon Janc3cf2a4f2011-03-01 16:55:33 +01001037 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
Johan Hedberg980e1a52011-01-22 06:10:07 +02001038 &cp->bdaddr);
1039 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001040 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001041
1042failed:
1043 hci_dev_unlock_bh(hdev);
1044 hci_dev_put(hdev);
1045
1046 return err;
1047}
1048
Szymon Janc4e51eae2011-02-25 19:05:48 +01001049static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1050 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001051{
1052 struct hci_dev *hdev;
1053 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001054
1055 BT_DBG("");
1056
1057 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001058
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001059 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001060 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001061
Szymon Janc4e51eae2011-02-25 19:05:48 +01001062 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001063 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001065
1066 hci_dev_lock_bh(hdev);
1067
1068 hdev->io_capability = cp->io_capability;
1069
1070 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001071 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001072
1073 hci_dev_unlock_bh(hdev);
1074 hci_dev_put(hdev);
1075
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001077}
1078
Johan Hedberge9a416b2011-02-19 12:05:56 -03001079static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1080{
1081 struct hci_dev *hdev = conn->hdev;
1082 struct list_head *p;
1083
1084 list_for_each(p, &cmd_list) {
1085 struct pending_cmd *cmd;
1086
1087 cmd = list_entry(p, struct pending_cmd, list);
1088
1089 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1090 continue;
1091
1092 if (cmd->index != hdev->id)
1093 continue;
1094
1095 if (cmd->user_data != conn)
1096 continue;
1097
1098 return cmd;
1099 }
1100
1101 return NULL;
1102}
1103
1104static void pairing_complete(struct pending_cmd *cmd, u8 status)
1105{
1106 struct mgmt_rp_pair_device rp;
1107 struct hci_conn *conn = cmd->user_data;
1108
Johan Hedberge9a416b2011-02-19 12:05:56 -03001109 bacpy(&rp.bdaddr, &conn->dst);
1110 rp.status = status;
1111
Szymon Janc4e51eae2011-02-25 19:05:48 +01001112 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001113
1114 /* So we don't get further callbacks for this connection */
1115 conn->connect_cfm_cb = NULL;
1116 conn->security_cfm_cb = NULL;
1117 conn->disconn_cfm_cb = NULL;
1118
1119 hci_conn_put(conn);
1120
Johan Hedberga664b5b2011-02-19 12:06:02 -03001121 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001122}
1123
1124static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1125{
1126 struct pending_cmd *cmd;
1127
1128 BT_DBG("status %u", status);
1129
1130 cmd = find_pairing(conn);
1131 if (!cmd) {
1132 BT_DBG("Unable to find a pending command");
1133 return;
1134 }
1135
1136 pairing_complete(cmd, status);
1137}
1138
Szymon Janc4e51eae2011-02-25 19:05:48 +01001139static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001140{
1141 struct hci_dev *hdev;
1142 struct mgmt_cp_pair_device *cp;
1143 struct pending_cmd *cmd;
1144 u8 sec_level, auth_type;
1145 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001146 int err;
1147
1148 BT_DBG("");
1149
1150 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001151
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001152 if (len != sizeof(*cp))
1153 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1154
Szymon Janc4e51eae2011-02-25 19:05:48 +01001155 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001156 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001157 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001158
1159 hci_dev_lock_bh(hdev);
1160
1161 if (cp->io_cap == 0x03) {
1162 sec_level = BT_SECURITY_MEDIUM;
1163 auth_type = HCI_AT_DEDICATED_BONDING;
1164 } else {
1165 sec_level = BT_SECURITY_HIGH;
1166 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1167 }
1168
1169 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001170 if (IS_ERR(conn)) {
1171 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001172 goto unlock;
1173 }
1174
1175 if (conn->connect_cfm_cb) {
1176 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001178 goto unlock;
1179 }
1180
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001182 if (!cmd) {
1183 err = -ENOMEM;
1184 hci_conn_put(conn);
1185 goto unlock;
1186 }
1187
1188 conn->connect_cfm_cb = pairing_complete_cb;
1189 conn->security_cfm_cb = pairing_complete_cb;
1190 conn->disconn_cfm_cb = pairing_complete_cb;
1191 conn->io_capability = cp->io_cap;
1192 cmd->user_data = conn;
1193
1194 if (conn->state == BT_CONNECTED &&
1195 hci_conn_security(conn, sec_level, auth_type))
1196 pairing_complete(cmd, 0);
1197
1198 err = 0;
1199
1200unlock:
1201 hci_dev_unlock_bh(hdev);
1202 hci_dev_put(hdev);
1203
1204 return err;
1205}
1206
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1208 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001209{
1210 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001212 struct pending_cmd *cmd;
1213 struct hci_dev *hdev;
1214 int err;
1215
1216 BT_DBG("");
1217
Johan Hedberga5c29682011-02-19 12:05:57 -03001218 if (success) {
1219 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1220 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1221 } else {
1222 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1223 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1224 }
1225
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001226 if (len != sizeof(*cp))
1227 return cmd_status(sk, index, mgmt_op, EINVAL);
1228
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001230 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001231 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001232
Johan Hedberg6994ca52011-03-16 14:29:34 +02001233 hci_dev_lock_bh(hdev);
1234
Johan Hedberga5c29682011-02-19 12:05:57 -03001235 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001236 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001237 goto failed;
1238 }
1239
Szymon Janc4e51eae2011-02-25 19:05:48 +01001240 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001241 if (!cmd) {
1242 err = -ENOMEM;
1243 goto failed;
1244 }
1245
1246 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001247 if (err < 0)
1248 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001249
1250failed:
1251 hci_dev_unlock_bh(hdev);
1252 hci_dev_put(hdev);
1253
1254 return err;
1255}
1256
Johan Hedberg03811012010-12-08 00:21:06 +02001257int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1258{
1259 unsigned char *buf;
1260 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001262 int err;
1263
1264 BT_DBG("got %zu bytes", msglen);
1265
1266 if (msglen < sizeof(*hdr))
1267 return -EINVAL;
1268
1269 buf = kmalloc(msglen, GFP_ATOMIC);
1270 if (!buf)
1271 return -ENOMEM;
1272
1273 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1274 err = -EFAULT;
1275 goto done;
1276 }
1277
1278 hdr = (struct mgmt_hdr *) buf;
1279 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001280 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001281 len = get_unaligned_le16(&hdr->len);
1282
1283 if (len != msglen - sizeof(*hdr)) {
1284 err = -EINVAL;
1285 goto done;
1286 }
1287
1288 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001289 case MGMT_OP_READ_VERSION:
1290 err = read_version(sk);
1291 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001292 case MGMT_OP_READ_INDEX_LIST:
1293 err = read_index_list(sk);
1294 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001295 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001297 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001298 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001299 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001300 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001301 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001302 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001303 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001304 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001305 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001306 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001307 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001308 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001309 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001311 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 break;
1313 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001314 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001315 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001316 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001318 break;
1319 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001320 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001321 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001322 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001324 break;
1325 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001327 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001328 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001329 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001330 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001331 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001332 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001333 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001335 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336 break;
1337 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001338 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001340 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001341 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001342 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001346 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001347 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001348 break;
1349 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001350 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001351 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001352 default:
1353 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001354 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001355 break;
1356 }
1357
Johan Hedberge41d8b42010-12-13 21:07:03 +02001358 if (err < 0)
1359 goto done;
1360
Johan Hedberg03811012010-12-08 00:21:06 +02001361 err = msglen;
1362
1363done:
1364 kfree(buf);
1365 return err;
1366}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001367
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001368int mgmt_index_added(u16 index)
1369{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001370 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001371}
1372
1373int mgmt_index_removed(u16 index)
1374{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001375 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001376}
1377
Johan Hedberg73f22f62010-12-29 16:00:25 +02001378struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001379 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001380 struct sock *sk;
1381};
1382
Johan Hedberg72a734e2010-12-30 00:38:22 +02001383static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001384{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001385 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001386 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001387
Johan Hedberg72a734e2010-12-30 00:38:22 +02001388 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389 return;
1390
Johan Hedberg053f0212011-01-26 13:07:10 +02001391 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001392
1393 list_del(&cmd->list);
1394
1395 if (match->sk == NULL) {
1396 match->sk = cmd->sk;
1397 sock_hold(match->sk);
1398 }
1399
1400 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001401}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001402
1403int mgmt_powered(u16 index, u8 powered)
1404{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001405 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001406 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001407 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001408
Johan Hedberg72a734e2010-12-30 00:38:22 +02001409 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001410
Johan Hedberg72a734e2010-12-30 00:38:22 +02001411 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001414
1415 if (match.sk)
1416 sock_put(match.sk);
1417
1418 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001419}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001420
Johan Hedberg73f22f62010-12-29 16:00:25 +02001421int mgmt_discoverable(u16 index, u8 discoverable)
1422{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001423 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001424 struct cmd_lookup match = { discoverable, NULL };
1425 int ret;
1426
Szymon Jancb8534e02011-03-01 16:55:34 +01001427 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001428
Johan Hedberg72a734e2010-12-30 00:38:22 +02001429 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001430
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1432 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001433
1434 if (match.sk)
1435 sock_put(match.sk);
1436
1437 return ret;
1438}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001439
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001440int mgmt_connectable(u16 index, u8 connectable)
1441{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001442 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001443 struct cmd_lookup match = { connectable, NULL };
1444 int ret;
1445
Johan Hedberg72a734e2010-12-30 00:38:22 +02001446 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001447
Johan Hedberg72a734e2010-12-30 00:38:22 +02001448 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001449
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001451
1452 if (match.sk)
1453 sock_put(match.sk);
1454
1455 return ret;
1456}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457
1458int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1459{
1460 struct mgmt_ev_new_key ev;
1461
1462 memset(&ev, 0, sizeof(ev));
1463
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464 bacpy(&ev.key.bdaddr, &key->bdaddr);
1465 ev.key.type = key->type;
1466 memcpy(ev.key.val, key->val, 16);
1467 ev.key.pin_len = key->pin_len;
1468 ev.old_key_type = old_key_type;
1469
Szymon Janc4e51eae2011-02-25 19:05:48 +01001470 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001471}
Johan Hedbergf7520542011-01-20 12:34:39 +02001472
1473int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1474{
1475 struct mgmt_ev_connected ev;
1476
Johan Hedbergf7520542011-01-20 12:34:39 +02001477 bacpy(&ev.bdaddr, bdaddr);
1478
Szymon Janc4e51eae2011-02-25 19:05:48 +01001479 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001480}
1481
Johan Hedberg8962ee72011-01-20 12:40:27 +02001482static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1483{
1484 struct mgmt_cp_disconnect *cp = cmd->cmd;
1485 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001486 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001487
Johan Hedberga38528f2011-01-22 06:46:43 +02001488 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489
Szymon Janc4e51eae2011-02-25 19:05:48 +01001490 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491
1492 *sk = cmd->sk;
1493 sock_hold(*sk);
1494
Johan Hedberga664b5b2011-02-19 12:06:02 -03001495 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001496}
1497
Johan Hedbergf7520542011-01-20 12:34:39 +02001498int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1499{
1500 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001501 struct sock *sk = NULL;
1502 int err;
1503
1504 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001505
Johan Hedbergf7520542011-01-20 12:34:39 +02001506 bacpy(&ev.bdaddr, bdaddr);
1507
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001509
1510 if (sk)
1511 sock_put(sk);
1512
1513 return err;
1514}
1515
1516int mgmt_disconnect_failed(u16 index)
1517{
1518 struct pending_cmd *cmd;
1519 int err;
1520
1521 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1522 if (!cmd)
1523 return -ENOENT;
1524
Szymon Janc4e51eae2011-02-25 19:05:48 +01001525 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001526
Johan Hedberga664b5b2011-02-19 12:06:02 -03001527 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001528
1529 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001530}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001531
1532int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1533{
1534 struct mgmt_ev_connect_failed ev;
1535
Johan Hedberg17d5c042011-01-22 06:09:08 +02001536 bacpy(&ev.bdaddr, bdaddr);
1537 ev.status = status;
1538
Szymon Janc4e51eae2011-02-25 19:05:48 +01001539 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001540}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001541
1542int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1543{
1544 struct mgmt_ev_pin_code_request ev;
1545
Johan Hedberg980e1a52011-01-22 06:10:07 +02001546 bacpy(&ev.bdaddr, bdaddr);
1547
Szymon Janc4e51eae2011-02-25 19:05:48 +01001548 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1549 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001550}
1551
1552int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1553{
1554 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001555 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001556 int err;
1557
1558 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1559 if (!cmd)
1560 return -ENOENT;
1561
Johan Hedbergac56fb12011-02-19 12:05:59 -03001562 bacpy(&rp.bdaddr, bdaddr);
1563 rp.status = status;
1564
Szymon Janc4e51eae2011-02-25 19:05:48 +01001565 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1566 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001567
Johan Hedberga664b5b2011-02-19 12:06:02 -03001568 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001569
1570 return err;
1571}
1572
1573int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1574{
1575 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001576 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001577 int err;
1578
1579 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1580 if (!cmd)
1581 return -ENOENT;
1582
Johan Hedbergac56fb12011-02-19 12:05:59 -03001583 bacpy(&rp.bdaddr, bdaddr);
1584 rp.status = status;
1585
Szymon Janc4e51eae2011-02-25 19:05:48 +01001586 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1587 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001588
Johan Hedberga664b5b2011-02-19 12:06:02 -03001589 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001590
1591 return err;
1592}
Johan Hedberga5c29682011-02-19 12:05:57 -03001593
1594int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1595{
1596 struct mgmt_ev_user_confirm_request ev;
1597
1598 BT_DBG("hci%u", index);
1599
Johan Hedberga5c29682011-02-19 12:05:57 -03001600 bacpy(&ev.bdaddr, bdaddr);
1601 put_unaligned_le32(value, &ev.value);
1602
Szymon Janc4e51eae2011-02-25 19:05:48 +01001603 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1604 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001605}
1606
1607static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1608 u8 opcode)
1609{
1610 struct pending_cmd *cmd;
1611 struct mgmt_rp_user_confirm_reply rp;
1612 int err;
1613
1614 cmd = mgmt_pending_find(opcode, index);
1615 if (!cmd)
1616 return -ENOENT;
1617
Johan Hedberga5c29682011-02-19 12:05:57 -03001618 bacpy(&rp.bdaddr, bdaddr);
1619 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001620 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001621
Johan Hedberga664b5b2011-02-19 12:06:02 -03001622 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001623
1624 return err;
1625}
1626
1627int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1628{
1629 return confirm_reply_complete(index, bdaddr, status,
1630 MGMT_OP_USER_CONFIRM_REPLY);
1631}
1632
Szymon Jancb8534e02011-03-01 16:55:34 +01001633int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001634{
1635 return confirm_reply_complete(index, bdaddr, status,
1636 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1637}
Johan Hedberg2a611692011-02-19 12:06:00 -03001638
1639int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1640{
1641 struct mgmt_ev_auth_failed ev;
1642
Johan Hedberg2a611692011-02-19 12:06:00 -03001643 bacpy(&ev.bdaddr, bdaddr);
1644 ev.status = status;
1645
Szymon Janc4e51eae2011-02-25 19:05:48 +01001646 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001647}