blob: 6dd015277f0d334b57a9dbf533e2caa6e4e1af0c [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))
719 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
720 EINVAL);
721
Szymon Janc4e51eae2011-02-25 19:05:48 +0100722 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200723 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100724 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200725
726 hci_dev_lock_bh(hdev);
727
Szymon Janc4e51eae2011-02-25 19:05:48 +0100728 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200729
730 if (cp->enable) {
731 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
732 err = 0;
733 } else {
734 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
735 err = update_class(hdev);
736 }
737
738 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100739 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
740 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200741
742 hci_dev_unlock_bh(hdev);
743 hci_dev_put(hdev);
744
745 return err;
746}
747
Szymon Janc4e51eae2011-02-25 19:05:48 +0100748static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200749{
750 struct hci_dev *hdev;
751 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100752 u16 key_count, expected_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200753 int i;
754
755 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100756
757 if (len < sizeof(*cp))
758 return -EINVAL;
759
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200760 key_count = get_unaligned_le16(&cp->key_count);
761
762 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
763 if (expected_len != len) {
764 BT_ERR("load_keys: expected %u bytes, got %u bytes",
765 len, expected_len);
766 return -EINVAL;
767 }
768
Szymon Janc4e51eae2011-02-25 19:05:48 +0100769 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200770 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100771 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200772
Szymon Janc4e51eae2011-02-25 19:05:48 +0100773 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200774 key_count);
775
776 hci_dev_lock_bh(hdev);
777
778 hci_link_keys_clear(hdev);
779
780 set_bit(HCI_LINK_KEYS, &hdev->flags);
781
782 if (cp->debug_keys)
783 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
784 else
785 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
786
787 for (i = 0; i < key_count; i++) {
788 struct mgmt_key_info *key = &cp->keys[i];
789
790 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
791 key->pin_len);
792 }
793
794 hci_dev_unlock_bh(hdev);
795 hci_dev_put(hdev);
796
797 return 0;
798}
799
Szymon Janc4e51eae2011-02-25 19:05:48 +0100800static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200801{
802 struct hci_dev *hdev;
803 struct mgmt_cp_remove_key *cp;
804 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200805 int err;
806
807 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200808
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100809 if (len != sizeof(*cp))
810 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
811
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200813 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100814 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200815
816 hci_dev_lock_bh(hdev);
817
818 err = hci_remove_link_key(hdev, &cp->bdaddr);
819 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100820 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200821 goto unlock;
822 }
823
824 err = 0;
825
826 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
827 goto unlock;
828
829 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
830 if (conn) {
831 struct hci_cp_disconnect dc;
832
833 put_unaligned_le16(conn->handle, &dc.handle);
834 dc.reason = 0x13; /* Remote User Terminated Connection */
835 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
836 }
837
838unlock:
839 hci_dev_unlock_bh(hdev);
840 hci_dev_put(hdev);
841
842 return err;
843}
844
Szymon Janc4e51eae2011-02-25 19:05:48 +0100845static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200846{
847 struct hci_dev *hdev;
848 struct mgmt_cp_disconnect *cp;
849 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300850 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200851 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200852 int err;
853
854 BT_DBG("");
855
856 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200857
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100858 if (len != sizeof(*cp))
859 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
860
Szymon Janc4e51eae2011-02-25 19:05:48 +0100861 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200862 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100863 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200864
865 hci_dev_lock_bh(hdev);
866
867 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100868 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200869 goto failed;
870 }
871
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
873 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200874 goto failed;
875 }
876
877 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
878 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200880 goto failed;
881 }
882
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300884 if (!cmd) {
885 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200886 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300887 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200888
889 put_unaligned_le16(conn->handle, &dc.handle);
890 dc.reason = 0x13; /* Remote User Terminated Connection */
891
892 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
893 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300894 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200895
896failed:
897 hci_dev_unlock_bh(hdev);
898 hci_dev_put(hdev);
899
900 return err;
901}
902
Szymon Janc8ce62842011-03-01 16:55:32 +0100903static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200904{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200905 struct mgmt_rp_get_connections *rp;
906 struct hci_dev *hdev;
907 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200908 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200910 int i, err;
911
912 BT_DBG("");
913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200915 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200917
918 hci_dev_lock_bh(hdev);
919
920 count = 0;
921 list_for_each(p, &hdev->conn_hash.list) {
922 count++;
923 }
924
Johan Hedberga38528f2011-01-22 06:46:43 +0200925 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
926 rp = kmalloc(rp_len, GFP_ATOMIC);
927 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200928 err = -ENOMEM;
929 goto unlock;
930 }
931
Johan Hedberg2784eb42011-01-21 13:56:35 +0200932 put_unaligned_le16(count, &rp->conn_count);
933
934 read_lock(&hci_dev_list_lock);
935
936 i = 0;
937 list_for_each(p, &hdev->conn_hash.list) {
938 struct hci_conn *c = list_entry(p, struct hci_conn, list);
939
940 bacpy(&rp->conn[i++], &c->dst);
941 }
942
943 read_unlock(&hci_dev_list_lock);
944
Szymon Janc4e51eae2011-02-25 19:05:48 +0100945 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200946
947unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200948 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200949 hci_dev_unlock_bh(hdev);
950 hci_dev_put(hdev);
951 return err;
952}
953
Szymon Janc4e51eae2011-02-25 19:05:48 +0100954static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
955 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200956{
957 struct hci_dev *hdev;
958 struct mgmt_cp_pin_code_reply *cp;
959 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300960 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200961 int err;
962
963 BT_DBG("");
964
965 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200966
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100967 if (len != sizeof(*cp))
968 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
969
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200971 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100972 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200973
974 hci_dev_lock_bh(hdev);
975
976 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200978 goto failed;
979 }
980
Szymon Janc4e51eae2011-02-25 19:05:48 +0100981 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300982 if (!cmd) {
983 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200984 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300985 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200986
987 bacpy(&reply.bdaddr, &cp->bdaddr);
988 reply.pin_len = cp->pin_len;
989 memcpy(reply.pin_code, cp->pin_code, 16);
990
991 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
992 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300993 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200994
995failed:
996 hci_dev_unlock_bh(hdev);
997 hci_dev_put(hdev);
998
999 return err;
1000}
1001
Szymon Janc4e51eae2011-02-25 19:05:48 +01001002static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1003 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001004{
1005 struct hci_dev *hdev;
1006 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001007 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001008 int err;
1009
1010 BT_DBG("");
1011
1012 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001013
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001014 if (len != sizeof(*cp))
1015 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1016 EINVAL);
1017
Szymon Janc4e51eae2011-02-25 19:05:48 +01001018 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001019 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1021 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001022
1023 hci_dev_lock_bh(hdev);
1024
1025 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001026 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1027 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001028 goto failed;
1029 }
1030
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001032 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001033 if (!cmd) {
1034 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001035 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001036 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001037
1038 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1039 &cp->bdaddr);
1040 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001041 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001042
1043failed:
1044 hci_dev_unlock_bh(hdev);
1045 hci_dev_put(hdev);
1046
1047 return err;
1048}
1049
Szymon Janc4e51eae2011-02-25 19:05:48 +01001050static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1051 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001052{
1053 struct hci_dev *hdev;
1054 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001055
1056 BT_DBG("");
1057
1058 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001059
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001060 if (len != sizeof(*cp))
1061 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1062 EINVAL);
1063
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001065 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001066 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001067
1068 hci_dev_lock_bh(hdev);
1069
1070 hdev->io_capability = cp->io_capability;
1071
1072 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1073 hdev->io_capability);
1074
1075 hci_dev_unlock_bh(hdev);
1076 hci_dev_put(hdev);
1077
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001079}
1080
Johan Hedberge9a416b2011-02-19 12:05:56 -03001081static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1082{
1083 struct hci_dev *hdev = conn->hdev;
1084 struct list_head *p;
1085
1086 list_for_each(p, &cmd_list) {
1087 struct pending_cmd *cmd;
1088
1089 cmd = list_entry(p, struct pending_cmd, list);
1090
1091 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1092 continue;
1093
1094 if (cmd->index != hdev->id)
1095 continue;
1096
1097 if (cmd->user_data != conn)
1098 continue;
1099
1100 return cmd;
1101 }
1102
1103 return NULL;
1104}
1105
1106static void pairing_complete(struct pending_cmd *cmd, u8 status)
1107{
1108 struct mgmt_rp_pair_device rp;
1109 struct hci_conn *conn = cmd->user_data;
1110
Johan Hedberge9a416b2011-02-19 12:05:56 -03001111 bacpy(&rp.bdaddr, &conn->dst);
1112 rp.status = status;
1113
Szymon Janc4e51eae2011-02-25 19:05:48 +01001114 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001115
1116 /* So we don't get further callbacks for this connection */
1117 conn->connect_cfm_cb = NULL;
1118 conn->security_cfm_cb = NULL;
1119 conn->disconn_cfm_cb = NULL;
1120
1121 hci_conn_put(conn);
1122
Johan Hedberga664b5b2011-02-19 12:06:02 -03001123 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001124}
1125
1126static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1127{
1128 struct pending_cmd *cmd;
1129
1130 BT_DBG("status %u", status);
1131
1132 cmd = find_pairing(conn);
1133 if (!cmd) {
1134 BT_DBG("Unable to find a pending command");
1135 return;
1136 }
1137
1138 pairing_complete(cmd, status);
1139}
1140
Szymon Janc4e51eae2011-02-25 19:05:48 +01001141static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001142{
1143 struct hci_dev *hdev;
1144 struct mgmt_cp_pair_device *cp;
1145 struct pending_cmd *cmd;
1146 u8 sec_level, auth_type;
1147 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001148 int err;
1149
1150 BT_DBG("");
1151
1152 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001153
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001154 if (len != sizeof(*cp))
1155 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1156
Szymon Janc4e51eae2011-02-25 19:05:48 +01001157 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001158 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001160
1161 hci_dev_lock_bh(hdev);
1162
1163 if (cp->io_cap == 0x03) {
1164 sec_level = BT_SECURITY_MEDIUM;
1165 auth_type = HCI_AT_DEDICATED_BONDING;
1166 } else {
1167 sec_level = BT_SECURITY_HIGH;
1168 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1169 }
1170
1171 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001172 if (IS_ERR(conn)) {
1173 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001174 goto unlock;
1175 }
1176
1177 if (conn->connect_cfm_cb) {
1178 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001180 goto unlock;
1181 }
1182
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001184 if (!cmd) {
1185 err = -ENOMEM;
1186 hci_conn_put(conn);
1187 goto unlock;
1188 }
1189
1190 conn->connect_cfm_cb = pairing_complete_cb;
1191 conn->security_cfm_cb = pairing_complete_cb;
1192 conn->disconn_cfm_cb = pairing_complete_cb;
1193 conn->io_capability = cp->io_cap;
1194 cmd->user_data = conn;
1195
1196 if (conn->state == BT_CONNECTED &&
1197 hci_conn_security(conn, sec_level, auth_type))
1198 pairing_complete(cmd, 0);
1199
1200 err = 0;
1201
1202unlock:
1203 hci_dev_unlock_bh(hdev);
1204 hci_dev_put(hdev);
1205
1206 return err;
1207}
1208
Szymon Janc4e51eae2011-02-25 19:05:48 +01001209static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1210 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001211{
1212 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001214 struct pending_cmd *cmd;
1215 struct hci_dev *hdev;
1216 int err;
1217
1218 BT_DBG("");
1219
Johan Hedberga5c29682011-02-19 12:05:57 -03001220 if (success) {
1221 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1222 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1223 } else {
1224 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1225 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1226 }
1227
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001228 if (len != sizeof(*cp))
1229 return cmd_status(sk, index, mgmt_op, EINVAL);
1230
Szymon Janc4e51eae2011-02-25 19:05:48 +01001231 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001232 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001234
1235 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
Johan Hedberg73f22f62010-12-29 16:00:25 +02001427 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001428 mode_rsp, &match);
1429
Johan Hedberg72a734e2010-12-30 00:38:22 +02001430 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001431
Szymon Janc4e51eae2011-02-25 19:05:48 +01001432 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1433 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001434
1435 if (match.sk)
1436 sock_put(match.sk);
1437
1438 return ret;
1439}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001440
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001441int mgmt_connectable(u16 index, u8 connectable)
1442{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001443 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001444 struct cmd_lookup match = { connectable, NULL };
1445 int ret;
1446
Johan Hedberg72a734e2010-12-30 00:38:22 +02001447 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001448
Johan Hedberg72a734e2010-12-30 00:38:22 +02001449 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001450
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001452
1453 if (match.sk)
1454 sock_put(match.sk);
1455
1456 return ret;
1457}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001458
1459int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1460{
1461 struct mgmt_ev_new_key ev;
1462
1463 memset(&ev, 0, sizeof(ev));
1464
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465 bacpy(&ev.key.bdaddr, &key->bdaddr);
1466 ev.key.type = key->type;
1467 memcpy(ev.key.val, key->val, 16);
1468 ev.key.pin_len = key->pin_len;
1469 ev.old_key_type = old_key_type;
1470
Szymon Janc4e51eae2011-02-25 19:05:48 +01001471 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472}
Johan Hedbergf7520542011-01-20 12:34:39 +02001473
1474int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1475{
1476 struct mgmt_ev_connected ev;
1477
Johan Hedbergf7520542011-01-20 12:34:39 +02001478 bacpy(&ev.bdaddr, bdaddr);
1479
Szymon Janc4e51eae2011-02-25 19:05:48 +01001480 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001481}
1482
Johan Hedberg8962ee72011-01-20 12:40:27 +02001483static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1484{
1485 struct mgmt_cp_disconnect *cp = cmd->cmd;
1486 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001487 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488
Johan Hedberga38528f2011-01-22 06:46:43 +02001489 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001490
Szymon Janc4e51eae2011-02-25 19:05:48 +01001491 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001492
1493 *sk = cmd->sk;
1494 sock_hold(*sk);
1495
Johan Hedberga664b5b2011-02-19 12:06:02 -03001496 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001497}
1498
Johan Hedbergf7520542011-01-20 12:34:39 +02001499int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1500{
1501 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001502 struct sock *sk = NULL;
1503 int err;
1504
1505 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001506
Johan Hedbergf7520542011-01-20 12:34:39 +02001507 bacpy(&ev.bdaddr, bdaddr);
1508
Szymon Janc4e51eae2011-02-25 19:05:48 +01001509 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001510
1511 if (sk)
1512 sock_put(sk);
1513
1514 return err;
1515}
1516
1517int mgmt_disconnect_failed(u16 index)
1518{
1519 struct pending_cmd *cmd;
1520 int err;
1521
1522 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1523 if (!cmd)
1524 return -ENOENT;
1525
Szymon Janc4e51eae2011-02-25 19:05:48 +01001526 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001527
Johan Hedberga664b5b2011-02-19 12:06:02 -03001528 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001529
1530 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001531}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001532
1533int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1534{
1535 struct mgmt_ev_connect_failed ev;
1536
Johan Hedberg17d5c042011-01-22 06:09:08 +02001537 bacpy(&ev.bdaddr, bdaddr);
1538 ev.status = status;
1539
Szymon Janc4e51eae2011-02-25 19:05:48 +01001540 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001541}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001542
1543int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1544{
1545 struct mgmt_ev_pin_code_request ev;
1546
Johan Hedberg980e1a52011-01-22 06:10:07 +02001547 bacpy(&ev.bdaddr, bdaddr);
1548
Szymon Janc4e51eae2011-02-25 19:05:48 +01001549 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1550 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001551}
1552
1553int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1554{
1555 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001556 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001557 int err;
1558
1559 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1560 if (!cmd)
1561 return -ENOENT;
1562
Johan Hedbergac56fb12011-02-19 12:05:59 -03001563 bacpy(&rp.bdaddr, bdaddr);
1564 rp.status = status;
1565
Szymon Janc4e51eae2011-02-25 19:05:48 +01001566 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1567 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001568
Johan Hedberga664b5b2011-02-19 12:06:02 -03001569 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001570
1571 return err;
1572}
1573
1574int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1575{
1576 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001577 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001578 int err;
1579
1580 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1581 if (!cmd)
1582 return -ENOENT;
1583
Johan Hedbergac56fb12011-02-19 12:05:59 -03001584 bacpy(&rp.bdaddr, bdaddr);
1585 rp.status = status;
1586
Szymon Janc4e51eae2011-02-25 19:05:48 +01001587 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1588 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001589
Johan Hedberga664b5b2011-02-19 12:06:02 -03001590 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001591
1592 return err;
1593}
Johan Hedberga5c29682011-02-19 12:05:57 -03001594
1595int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1596{
1597 struct mgmt_ev_user_confirm_request ev;
1598
1599 BT_DBG("hci%u", index);
1600
Johan Hedberga5c29682011-02-19 12:05:57 -03001601 bacpy(&ev.bdaddr, bdaddr);
1602 put_unaligned_le32(value, &ev.value);
1603
Szymon Janc4e51eae2011-02-25 19:05:48 +01001604 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1605 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001606}
1607
1608static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1609 u8 opcode)
1610{
1611 struct pending_cmd *cmd;
1612 struct mgmt_rp_user_confirm_reply rp;
1613 int err;
1614
1615 cmd = mgmt_pending_find(opcode, index);
1616 if (!cmd)
1617 return -ENOENT;
1618
Johan Hedberga5c29682011-02-19 12:05:57 -03001619 bacpy(&rp.bdaddr, bdaddr);
1620 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001621 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001622
Johan Hedberga664b5b2011-02-19 12:06:02 -03001623 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001624
1625 return err;
1626}
1627
1628int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1629{
1630 return confirm_reply_complete(index, bdaddr, status,
1631 MGMT_OP_USER_CONFIRM_REPLY);
1632}
1633
1634int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1635 u8 status)
1636{
1637 return confirm_reply_complete(index, bdaddr, status,
1638 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1639}
Johan Hedberg2a611692011-02-19 12:06:00 -03001640
1641int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1642{
1643 struct mgmt_ev_auth_failed ev;
1644
Johan Hedberg2a611692011-02-19 12:06:00 -03001645 bacpy(&ev.bdaddr, bdaddr);
1646 ev.status = status;
1647
Szymon Janc4e51eae2011-02-25 19:05:48 +01001648 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001649}