blob: 0054c74e27b7fcd4971477408721b003e773f37a [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
1233 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001234 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001235 goto failed;
1236 }
1237
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001239 if (!cmd) {
1240 err = -ENOMEM;
1241 goto failed;
1242 }
1243
1244 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001245 if (err < 0)
1246 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001247
1248failed:
1249 hci_dev_unlock_bh(hdev);
1250 hci_dev_put(hdev);
1251
1252 return err;
1253}
1254
Johan Hedberg03811012010-12-08 00:21:06 +02001255int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1256{
1257 unsigned char *buf;
1258 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001259 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001260 int err;
1261
1262 BT_DBG("got %zu bytes", msglen);
1263
1264 if (msglen < sizeof(*hdr))
1265 return -EINVAL;
1266
1267 buf = kmalloc(msglen, GFP_ATOMIC);
1268 if (!buf)
1269 return -ENOMEM;
1270
1271 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1272 err = -EFAULT;
1273 goto done;
1274 }
1275
1276 hdr = (struct mgmt_hdr *) buf;
1277 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001279 len = get_unaligned_le16(&hdr->len);
1280
1281 if (len != msglen - sizeof(*hdr)) {
1282 err = -EINVAL;
1283 goto done;
1284 }
1285
1286 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001287 case MGMT_OP_READ_VERSION:
1288 err = read_version(sk);
1289 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001290 case MGMT_OP_READ_INDEX_LIST:
1291 err = read_index_list(sk);
1292 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001293 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001295 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001296 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001297 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001298 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001299 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001301 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001302 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001304 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001305 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001307 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001309 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310 break;
1311 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001312 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001314 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001316 break;
1317 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001318 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001319 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001320 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001322 break;
1323 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001324 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001325 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001326 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001328 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001329 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001330 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001331 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001332 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001333 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334 break;
1335 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001336 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001337 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001338 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001340 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001341 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001344 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001346 break;
1347 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001348 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001349 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001350 default:
1351 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001353 break;
1354 }
1355
Johan Hedberge41d8b42010-12-13 21:07:03 +02001356 if (err < 0)
1357 goto done;
1358
Johan Hedberg03811012010-12-08 00:21:06 +02001359 err = msglen;
1360
1361done:
1362 kfree(buf);
1363 return err;
1364}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001365
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001366int mgmt_index_added(u16 index)
1367{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001368 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001369}
1370
1371int mgmt_index_removed(u16 index)
1372{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001373 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001374}
1375
Johan Hedberg73f22f62010-12-29 16:00:25 +02001376struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001377 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001378 struct sock *sk;
1379};
1380
Johan Hedberg72a734e2010-12-30 00:38:22 +02001381static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001382{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001383 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001384 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001385
Johan Hedberg72a734e2010-12-30 00:38:22 +02001386 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001387 return;
1388
Johan Hedberg053f0212011-01-26 13:07:10 +02001389 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001390
1391 list_del(&cmd->list);
1392
1393 if (match->sk == NULL) {
1394 match->sk = cmd->sk;
1395 sock_hold(match->sk);
1396 }
1397
1398 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001399}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001400
1401int mgmt_powered(u16 index, u8 powered)
1402{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001403 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001404 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001405 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001406
Johan Hedberg72a734e2010-12-30 00:38:22 +02001407 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001408
Johan Hedberg72a734e2010-12-30 00:38:22 +02001409 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001410
Szymon Janc4e51eae2011-02-25 19:05:48 +01001411 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001412
1413 if (match.sk)
1414 sock_put(match.sk);
1415
1416 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001417}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001418
Johan Hedberg73f22f62010-12-29 16:00:25 +02001419int mgmt_discoverable(u16 index, u8 discoverable)
1420{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001421 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422 struct cmd_lookup match = { discoverable, NULL };
1423 int ret;
1424
Szymon Jancb8534e02011-03-01 16:55:34 +01001425 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001426
Johan Hedberg72a734e2010-12-30 00:38:22 +02001427 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001428
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1430 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001431
1432 if (match.sk)
1433 sock_put(match.sk);
1434
1435 return ret;
1436}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001437
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001438int mgmt_connectable(u16 index, u8 connectable)
1439{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001440 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001441 struct cmd_lookup match = { connectable, NULL };
1442 int ret;
1443
Johan Hedberg72a734e2010-12-30 00:38:22 +02001444 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001445
Johan Hedberg72a734e2010-12-30 00:38:22 +02001446 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001447
Szymon Janc4e51eae2011-02-25 19:05:48 +01001448 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001449
1450 if (match.sk)
1451 sock_put(match.sk);
1452
1453 return ret;
1454}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001455
1456int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1457{
1458 struct mgmt_ev_new_key ev;
1459
1460 memset(&ev, 0, sizeof(ev));
1461
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001462 bacpy(&ev.key.bdaddr, &key->bdaddr);
1463 ev.key.type = key->type;
1464 memcpy(ev.key.val, key->val, 16);
1465 ev.key.pin_len = key->pin_len;
1466 ev.old_key_type = old_key_type;
1467
Szymon Janc4e51eae2011-02-25 19:05:48 +01001468 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469}
Johan Hedbergf7520542011-01-20 12:34:39 +02001470
1471int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1472{
1473 struct mgmt_ev_connected ev;
1474
Johan Hedbergf7520542011-01-20 12:34:39 +02001475 bacpy(&ev.bdaddr, bdaddr);
1476
Szymon Janc4e51eae2011-02-25 19:05:48 +01001477 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001478}
1479
Johan Hedberg8962ee72011-01-20 12:40:27 +02001480static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1481{
1482 struct mgmt_cp_disconnect *cp = cmd->cmd;
1483 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001484 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001485
Johan Hedberga38528f2011-01-22 06:46:43 +02001486 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001487
Szymon Janc4e51eae2011-02-25 19:05:48 +01001488 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489
1490 *sk = cmd->sk;
1491 sock_hold(*sk);
1492
Johan Hedberga664b5b2011-02-19 12:06:02 -03001493 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494}
1495
Johan Hedbergf7520542011-01-20 12:34:39 +02001496int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1497{
1498 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001499 struct sock *sk = NULL;
1500 int err;
1501
1502 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001503
Johan Hedbergf7520542011-01-20 12:34:39 +02001504 bacpy(&ev.bdaddr, bdaddr);
1505
Szymon Janc4e51eae2011-02-25 19:05:48 +01001506 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001507
1508 if (sk)
1509 sock_put(sk);
1510
1511 return err;
1512}
1513
1514int mgmt_disconnect_failed(u16 index)
1515{
1516 struct pending_cmd *cmd;
1517 int err;
1518
1519 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1520 if (!cmd)
1521 return -ENOENT;
1522
Szymon Janc4e51eae2011-02-25 19:05:48 +01001523 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001524
Johan Hedberga664b5b2011-02-19 12:06:02 -03001525 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001526
1527 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001528}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001529
1530int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1531{
1532 struct mgmt_ev_connect_failed ev;
1533
Johan Hedberg17d5c042011-01-22 06:09:08 +02001534 bacpy(&ev.bdaddr, bdaddr);
1535 ev.status = status;
1536
Szymon Janc4e51eae2011-02-25 19:05:48 +01001537 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001538}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001539
1540int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1541{
1542 struct mgmt_ev_pin_code_request ev;
1543
Johan Hedberg980e1a52011-01-22 06:10:07 +02001544 bacpy(&ev.bdaddr, bdaddr);
1545
Szymon Janc4e51eae2011-02-25 19:05:48 +01001546 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1547 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001548}
1549
1550int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1551{
1552 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001553 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001554 int err;
1555
1556 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1557 if (!cmd)
1558 return -ENOENT;
1559
Johan Hedbergac56fb12011-02-19 12:05:59 -03001560 bacpy(&rp.bdaddr, bdaddr);
1561 rp.status = status;
1562
Szymon Janc4e51eae2011-02-25 19:05:48 +01001563 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1564 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001565
Johan Hedberga664b5b2011-02-19 12:06:02 -03001566 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001567
1568 return err;
1569}
1570
1571int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1572{
1573 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001574 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001575 int err;
1576
1577 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1578 if (!cmd)
1579 return -ENOENT;
1580
Johan Hedbergac56fb12011-02-19 12:05:59 -03001581 bacpy(&rp.bdaddr, bdaddr);
1582 rp.status = status;
1583
Szymon Janc4e51eae2011-02-25 19:05:48 +01001584 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1585 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001586
Johan Hedberga664b5b2011-02-19 12:06:02 -03001587 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001588
1589 return err;
1590}
Johan Hedberga5c29682011-02-19 12:05:57 -03001591
1592int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1593{
1594 struct mgmt_ev_user_confirm_request ev;
1595
1596 BT_DBG("hci%u", index);
1597
Johan Hedberga5c29682011-02-19 12:05:57 -03001598 bacpy(&ev.bdaddr, bdaddr);
1599 put_unaligned_le32(value, &ev.value);
1600
Szymon Janc4e51eae2011-02-25 19:05:48 +01001601 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1602 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001603}
1604
1605static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1606 u8 opcode)
1607{
1608 struct pending_cmd *cmd;
1609 struct mgmt_rp_user_confirm_reply rp;
1610 int err;
1611
1612 cmd = mgmt_pending_find(opcode, index);
1613 if (!cmd)
1614 return -ENOENT;
1615
Johan Hedberga5c29682011-02-19 12:05:57 -03001616 bacpy(&rp.bdaddr, bdaddr);
1617 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001618 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001619
Johan Hedberga664b5b2011-02-19 12:06:02 -03001620 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001621
1622 return err;
1623}
1624
1625int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1626{
1627 return confirm_reply_complete(index, bdaddr, status,
1628 MGMT_OP_USER_CONFIRM_REPLY);
1629}
1630
Szymon Jancb8534e02011-03-01 16:55:34 +01001631int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001632{
1633 return confirm_reply_complete(index, bdaddr, status,
1634 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1635}
Johan Hedberg2a611692011-02-19 12:06:00 -03001636
1637int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1638{
1639 struct mgmt_ev_auth_failed ev;
1640
Johan Hedberg2a611692011-02-19 12:06:00 -03001641 bacpy(&ev.bdaddr, bdaddr);
1642 ev.status = status;
1643
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001645}