blob: e6efaae764b38fd2c81826516061ad0f3ec6dc9d [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 Janc4e51eae2011-02-25 19:05:48 +0100903static int get_connections(struct sock *sk, u16 index, unsigned char *data,
904 u16 len)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200905{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200906 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200907 struct mgmt_rp_get_connections *rp;
908 struct hci_dev *hdev;
909 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200910 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200912 int i, err;
913
914 BT_DBG("");
915
916 cp = (void *) data;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200917
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200919 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200921
922 hci_dev_lock_bh(hdev);
923
924 count = 0;
925 list_for_each(p, &hdev->conn_hash.list) {
926 count++;
927 }
928
Johan Hedberga38528f2011-01-22 06:46:43 +0200929 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
930 rp = kmalloc(rp_len, GFP_ATOMIC);
931 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200932 err = -ENOMEM;
933 goto unlock;
934 }
935
Johan Hedberg2784eb42011-01-21 13:56:35 +0200936 put_unaligned_le16(count, &rp->conn_count);
937
938 read_lock(&hci_dev_list_lock);
939
940 i = 0;
941 list_for_each(p, &hdev->conn_hash.list) {
942 struct hci_conn *c = list_entry(p, struct hci_conn, list);
943
944 bacpy(&rp->conn[i++], &c->dst);
945 }
946
947 read_unlock(&hci_dev_list_lock);
948
Szymon Janc4e51eae2011-02-25 19:05:48 +0100949 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200950
951unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200952 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200953 hci_dev_unlock_bh(hdev);
954 hci_dev_put(hdev);
955 return err;
956}
957
Szymon Janc4e51eae2011-02-25 19:05:48 +0100958static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
959 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200960{
961 struct hci_dev *hdev;
962 struct mgmt_cp_pin_code_reply *cp;
963 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300964 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200965 int err;
966
967 BT_DBG("");
968
969 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200970
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100971 if (len != sizeof(*cp))
972 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
973
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200975 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200977
978 hci_dev_lock_bh(hdev);
979
980 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100981 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200982 goto failed;
983 }
984
Szymon Janc4e51eae2011-02-25 19:05:48 +0100985 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300986 if (!cmd) {
987 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200988 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300989 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200990
991 bacpy(&reply.bdaddr, &cp->bdaddr);
992 reply.pin_len = cp->pin_len;
993 memcpy(reply.pin_code, cp->pin_code, 16);
994
995 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
996 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300997 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200998
999failed:
1000 hci_dev_unlock_bh(hdev);
1001 hci_dev_put(hdev);
1002
1003 return err;
1004}
1005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1007 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001011 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001012 int err;
1013
1014 BT_DBG("");
1015
1016 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001017
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018 if (len != sizeof(*cp))
1019 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1020 EINVAL);
1021
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001023 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1025 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001026
1027 hci_dev_lock_bh(hdev);
1028
1029 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1031 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001032 goto failed;
1033 }
1034
Szymon Janc4e51eae2011-02-25 19:05:48 +01001035 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001036 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001037 if (!cmd) {
1038 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001039 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001040 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001041
1042 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1043 &cp->bdaddr);
1044 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001045 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001046
1047failed:
1048 hci_dev_unlock_bh(hdev);
1049 hci_dev_put(hdev);
1050
1051 return err;
1052}
1053
Szymon Janc4e51eae2011-02-25 19:05:48 +01001054static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1055 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001056{
1057 struct hci_dev *hdev;
1058 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001059
1060 BT_DBG("");
1061
1062 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001063
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001064 if (len != sizeof(*cp))
1065 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1066 EINVAL);
1067
Szymon Janc4e51eae2011-02-25 19:05:48 +01001068 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001069 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001071
1072 hci_dev_lock_bh(hdev);
1073
1074 hdev->io_capability = cp->io_capability;
1075
1076 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1077 hdev->io_capability);
1078
1079 hci_dev_unlock_bh(hdev);
1080 hci_dev_put(hdev);
1081
Szymon Janc4e51eae2011-02-25 19:05:48 +01001082 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001083}
1084
Johan Hedberge9a416b2011-02-19 12:05:56 -03001085static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1086{
1087 struct hci_dev *hdev = conn->hdev;
1088 struct list_head *p;
1089
1090 list_for_each(p, &cmd_list) {
1091 struct pending_cmd *cmd;
1092
1093 cmd = list_entry(p, struct pending_cmd, list);
1094
1095 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1096 continue;
1097
1098 if (cmd->index != hdev->id)
1099 continue;
1100
1101 if (cmd->user_data != conn)
1102 continue;
1103
1104 return cmd;
1105 }
1106
1107 return NULL;
1108}
1109
1110static void pairing_complete(struct pending_cmd *cmd, u8 status)
1111{
1112 struct mgmt_rp_pair_device rp;
1113 struct hci_conn *conn = cmd->user_data;
1114
Johan Hedberge9a416b2011-02-19 12:05:56 -03001115 bacpy(&rp.bdaddr, &conn->dst);
1116 rp.status = status;
1117
Szymon Janc4e51eae2011-02-25 19:05:48 +01001118 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001119
1120 /* So we don't get further callbacks for this connection */
1121 conn->connect_cfm_cb = NULL;
1122 conn->security_cfm_cb = NULL;
1123 conn->disconn_cfm_cb = NULL;
1124
1125 hci_conn_put(conn);
1126
Johan Hedberga664b5b2011-02-19 12:06:02 -03001127 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001128}
1129
1130static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1131{
1132 struct pending_cmd *cmd;
1133
1134 BT_DBG("status %u", status);
1135
1136 cmd = find_pairing(conn);
1137 if (!cmd) {
1138 BT_DBG("Unable to find a pending command");
1139 return;
1140 }
1141
1142 pairing_complete(cmd, status);
1143}
1144
Szymon Janc4e51eae2011-02-25 19:05:48 +01001145static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001146{
1147 struct hci_dev *hdev;
1148 struct mgmt_cp_pair_device *cp;
1149 struct pending_cmd *cmd;
1150 u8 sec_level, auth_type;
1151 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001152 int err;
1153
1154 BT_DBG("");
1155
1156 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001157
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001158 if (len != sizeof(*cp))
1159 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1160
Szymon Janc4e51eae2011-02-25 19:05:48 +01001161 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001162 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001163 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001164
1165 hci_dev_lock_bh(hdev);
1166
1167 if (cp->io_cap == 0x03) {
1168 sec_level = BT_SECURITY_MEDIUM;
1169 auth_type = HCI_AT_DEDICATED_BONDING;
1170 } else {
1171 sec_level = BT_SECURITY_HIGH;
1172 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1173 }
1174
1175 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001176 if (IS_ERR(conn)) {
1177 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001178 goto unlock;
1179 }
1180
1181 if (conn->connect_cfm_cb) {
1182 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001184 goto unlock;
1185 }
1186
Szymon Janc4e51eae2011-02-25 19:05:48 +01001187 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001188 if (!cmd) {
1189 err = -ENOMEM;
1190 hci_conn_put(conn);
1191 goto unlock;
1192 }
1193
1194 conn->connect_cfm_cb = pairing_complete_cb;
1195 conn->security_cfm_cb = pairing_complete_cb;
1196 conn->disconn_cfm_cb = pairing_complete_cb;
1197 conn->io_capability = cp->io_cap;
1198 cmd->user_data = conn;
1199
1200 if (conn->state == BT_CONNECTED &&
1201 hci_conn_security(conn, sec_level, auth_type))
1202 pairing_complete(cmd, 0);
1203
1204 err = 0;
1205
1206unlock:
1207 hci_dev_unlock_bh(hdev);
1208 hci_dev_put(hdev);
1209
1210 return err;
1211}
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1214 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001215{
1216 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001218 struct pending_cmd *cmd;
1219 struct hci_dev *hdev;
1220 int err;
1221
1222 BT_DBG("");
1223
Johan Hedberga5c29682011-02-19 12:05:57 -03001224 if (success) {
1225 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1226 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1227 } else {
1228 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1229 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1230 }
1231
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001232 if (len != sizeof(*cp))
1233 return cmd_status(sk, index, mgmt_op, EINVAL);
1234
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001236 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001238
1239 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001240 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001241 goto failed;
1242 }
1243
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001245 if (!cmd) {
1246 err = -ENOMEM;
1247 goto failed;
1248 }
1249
1250 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001251 if (err < 0)
1252 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001253
1254failed:
1255 hci_dev_unlock_bh(hdev);
1256 hci_dev_put(hdev);
1257
1258 return err;
1259}
1260
Johan Hedberg03811012010-12-08 00:21:06 +02001261int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1262{
1263 unsigned char *buf;
1264 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001266 int err;
1267
1268 BT_DBG("got %zu bytes", msglen);
1269
1270 if (msglen < sizeof(*hdr))
1271 return -EINVAL;
1272
1273 buf = kmalloc(msglen, GFP_ATOMIC);
1274 if (!buf)
1275 return -ENOMEM;
1276
1277 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1278 err = -EFAULT;
1279 goto done;
1280 }
1281
1282 hdr = (struct mgmt_hdr *) buf;
1283 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001284 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001285 len = get_unaligned_le16(&hdr->len);
1286
1287 if (len != msglen - sizeof(*hdr)) {
1288 err = -EINVAL;
1289 goto done;
1290 }
1291
1292 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001293 case MGMT_OP_READ_VERSION:
1294 err = read_version(sk);
1295 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001296 case MGMT_OP_READ_INDEX_LIST:
1297 err = read_index_list(sk);
1298 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001299 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001301 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001302 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001304 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001305 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001307 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001308 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001309 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001310 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001311 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001312 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001313 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001316 break;
1317 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001318 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001319 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001320 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001322 break;
1323 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001324 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001325 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001326 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001328 break;
1329 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001330 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001331 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001332 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001333 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001334 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001335 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001336 err = get_connections(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001337 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340 break;
1341 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001343 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001344 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001346 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001348 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001350 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001351 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001352 break;
1353 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001354 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001355 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001356 default:
1357 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001358 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001359 break;
1360 }
1361
Johan Hedberge41d8b42010-12-13 21:07:03 +02001362 if (err < 0)
1363 goto done;
1364
Johan Hedberg03811012010-12-08 00:21:06 +02001365 err = msglen;
1366
1367done:
1368 kfree(buf);
1369 return err;
1370}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001371
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001372int mgmt_index_added(u16 index)
1373{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001374 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001375}
1376
1377int mgmt_index_removed(u16 index)
1378{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001379 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001380}
1381
Johan Hedberg73f22f62010-12-29 16:00:25 +02001382struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001383 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001384 struct sock *sk;
1385};
1386
Johan Hedberg72a734e2010-12-30 00:38:22 +02001387static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001388{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001389 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001390 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001391
Johan Hedberg72a734e2010-12-30 00:38:22 +02001392 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001393 return;
1394
Johan Hedberg053f0212011-01-26 13:07:10 +02001395 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001396
1397 list_del(&cmd->list);
1398
1399 if (match->sk == NULL) {
1400 match->sk = cmd->sk;
1401 sock_hold(match->sk);
1402 }
1403
1404 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001405}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001406
1407int mgmt_powered(u16 index, u8 powered)
1408{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001409 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001410 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001411 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001412
Johan Hedberg72a734e2010-12-30 00:38:22 +02001413 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001414
Johan Hedberg72a734e2010-12-30 00:38:22 +02001415 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001416
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001418
1419 if (match.sk)
1420 sock_put(match.sk);
1421
1422 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001423}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001424
Johan Hedberg73f22f62010-12-29 16:00:25 +02001425int mgmt_discoverable(u16 index, u8 discoverable)
1426{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001427 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001428 struct cmd_lookup match = { discoverable, NULL };
1429 int ret;
1430
Johan Hedberg73f22f62010-12-29 16:00:25 +02001431 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001432 mode_rsp, &match);
1433
Johan Hedberg72a734e2010-12-30 00:38:22 +02001434 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001435
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1437 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001438
1439 if (match.sk)
1440 sock_put(match.sk);
1441
1442 return ret;
1443}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001444
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001445int mgmt_connectable(u16 index, u8 connectable)
1446{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001447 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001448 struct cmd_lookup match = { connectable, NULL };
1449 int ret;
1450
Johan Hedberg72a734e2010-12-30 00:38:22 +02001451 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001452
Johan Hedberg72a734e2010-12-30 00:38:22 +02001453 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001454
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001456
1457 if (match.sk)
1458 sock_put(match.sk);
1459
1460 return ret;
1461}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001462
1463int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1464{
1465 struct mgmt_ev_new_key ev;
1466
1467 memset(&ev, 0, sizeof(ev));
1468
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469 bacpy(&ev.key.bdaddr, &key->bdaddr);
1470 ev.key.type = key->type;
1471 memcpy(ev.key.val, key->val, 16);
1472 ev.key.pin_len = key->pin_len;
1473 ev.old_key_type = old_key_type;
1474
Szymon Janc4e51eae2011-02-25 19:05:48 +01001475 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476}
Johan Hedbergf7520542011-01-20 12:34:39 +02001477
1478int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1479{
1480 struct mgmt_ev_connected ev;
1481
Johan Hedbergf7520542011-01-20 12:34:39 +02001482 bacpy(&ev.bdaddr, bdaddr);
1483
Szymon Janc4e51eae2011-02-25 19:05:48 +01001484 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001485}
1486
Johan Hedberg8962ee72011-01-20 12:40:27 +02001487static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1488{
1489 struct mgmt_cp_disconnect *cp = cmd->cmd;
1490 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001491 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001492
Johan Hedberga38528f2011-01-22 06:46:43 +02001493 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494
Szymon Janc4e51eae2011-02-25 19:05:48 +01001495 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001496
1497 *sk = cmd->sk;
1498 sock_hold(*sk);
1499
Johan Hedberga664b5b2011-02-19 12:06:02 -03001500 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001501}
1502
Johan Hedbergf7520542011-01-20 12:34:39 +02001503int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1504{
1505 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001506 struct sock *sk = NULL;
1507 int err;
1508
1509 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001510
Johan Hedbergf7520542011-01-20 12:34:39 +02001511 bacpy(&ev.bdaddr, bdaddr);
1512
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001514
1515 if (sk)
1516 sock_put(sk);
1517
1518 return err;
1519}
1520
1521int mgmt_disconnect_failed(u16 index)
1522{
1523 struct pending_cmd *cmd;
1524 int err;
1525
1526 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1527 if (!cmd)
1528 return -ENOENT;
1529
Szymon Janc4e51eae2011-02-25 19:05:48 +01001530 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001531
Johan Hedberga664b5b2011-02-19 12:06:02 -03001532 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001533
1534 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001535}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001536
1537int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1538{
1539 struct mgmt_ev_connect_failed ev;
1540
Johan Hedberg17d5c042011-01-22 06:09:08 +02001541 bacpy(&ev.bdaddr, bdaddr);
1542 ev.status = status;
1543
Szymon Janc4e51eae2011-02-25 19:05:48 +01001544 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001545}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001546
1547int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1548{
1549 struct mgmt_ev_pin_code_request ev;
1550
Johan Hedberg980e1a52011-01-22 06:10:07 +02001551 bacpy(&ev.bdaddr, bdaddr);
1552
Szymon Janc4e51eae2011-02-25 19:05:48 +01001553 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1554 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001555}
1556
1557int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1558{
1559 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001560 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001561 int err;
1562
1563 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1564 if (!cmd)
1565 return -ENOENT;
1566
Johan Hedbergac56fb12011-02-19 12:05:59 -03001567 bacpy(&rp.bdaddr, bdaddr);
1568 rp.status = status;
1569
Szymon Janc4e51eae2011-02-25 19:05:48 +01001570 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1571 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001572
Johan Hedberga664b5b2011-02-19 12:06:02 -03001573 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001574
1575 return err;
1576}
1577
1578int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1579{
1580 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001581 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001582 int err;
1583
1584 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1585 if (!cmd)
1586 return -ENOENT;
1587
Johan Hedbergac56fb12011-02-19 12:05:59 -03001588 bacpy(&rp.bdaddr, bdaddr);
1589 rp.status = status;
1590
Szymon Janc4e51eae2011-02-25 19:05:48 +01001591 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1592 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001593
Johan Hedberga664b5b2011-02-19 12:06:02 -03001594 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001595
1596 return err;
1597}
Johan Hedberga5c29682011-02-19 12:05:57 -03001598
1599int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1600{
1601 struct mgmt_ev_user_confirm_request ev;
1602
1603 BT_DBG("hci%u", index);
1604
Johan Hedberga5c29682011-02-19 12:05:57 -03001605 bacpy(&ev.bdaddr, bdaddr);
1606 put_unaligned_le32(value, &ev.value);
1607
Szymon Janc4e51eae2011-02-25 19:05:48 +01001608 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1609 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001610}
1611
1612static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1613 u8 opcode)
1614{
1615 struct pending_cmd *cmd;
1616 struct mgmt_rp_user_confirm_reply rp;
1617 int err;
1618
1619 cmd = mgmt_pending_find(opcode, index);
1620 if (!cmd)
1621 return -ENOENT;
1622
Johan Hedberga5c29682011-02-19 12:05:57 -03001623 bacpy(&rp.bdaddr, bdaddr);
1624 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001625 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001626
Johan Hedberga664b5b2011-02-19 12:06:02 -03001627 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001628
1629 return err;
1630}
1631
1632int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1633{
1634 return confirm_reply_complete(index, bdaddr, status,
1635 MGMT_OP_USER_CONFIRM_REPLY);
1636}
1637
1638int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1639 u8 status)
1640{
1641 return confirm_reply_complete(index, bdaddr, status,
1642 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1643}
Johan Hedberg2a611692011-02-19 12:06:00 -03001644
1645int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1646{
1647 struct mgmt_ev_auth_failed ev;
1648
Johan Hedberg2a611692011-02-19 12:06:00 -03001649 bacpy(&ev.bdaddr, bdaddr);
1650 ev.status = status;
1651
Szymon Janc4e51eae2011-02-25 19:05:48 +01001652 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001653}