blob: ffdb2f4e8635dbc04b6330a279f58087f3515318 [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200179
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200180 hci_del_off_timer(hdev);
181
Johan Hedbergf7b64e62010-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 Hedbergdc4fe302011-03-16 14:29:36 +0200186 memset(&rp, 0, sizeof(rp));
187
Johan Hedberga38528f2011-01-22 06:46:43 +0200188 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200189
Johan Hedberga38528f2011-01-22 06:46:43 +0200190 rp.powered = test_bit(HCI_UP, &hdev->flags);
191 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
192 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
193 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200194
195 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 bacpy(&rp.bdaddr, &hdev->bdaddr);
203 memcpy(rp.features, hdev->features, 8);
204 memcpy(rp.dev_class, hdev->dev_class, 3);
205 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
206 rp.hci_ver = hdev->hci_ver;
207 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200209 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
210
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211 hci_dev_unlock_bh(hdev);
212 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200213
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200215}
216
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200217static void mgmt_pending_free(struct pending_cmd *cmd)
218{
219 sock_put(cmd->sk);
220 kfree(cmd->cmd);
221 kfree(cmd);
222}
223
Johan Hedberg366a0332011-02-19 12:05:55 -0300224static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
225 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200226{
227 struct pending_cmd *cmd;
228
229 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
230 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300231 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200232
233 cmd->opcode = opcode;
234 cmd->index = index;
235
236 cmd->cmd = kmalloc(len, GFP_ATOMIC);
237 if (!cmd->cmd) {
238 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300239 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200240 }
241
242 memcpy(cmd->cmd, data, len);
243
244 cmd->sk = sk;
245 sock_hold(sk);
246
247 list_add(&cmd->list, &cmd_list);
248
Johan Hedberg366a0332011-02-19 12:05:55 -0300249 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200250}
251
252static void mgmt_pending_foreach(u16 opcode, int index,
253 void (*cb)(struct pending_cmd *cmd, void *data),
254 void *data)
255{
256 struct list_head *p, *n;
257
258 list_for_each_safe(p, n, &cmd_list) {
259 struct pending_cmd *cmd;
260
261 cmd = list_entry(p, struct pending_cmd, list);
262
263 if (cmd->opcode != opcode)
264 continue;
265
266 if (index >= 0 && cmd->index != index)
267 continue;
268
269 cb(cmd, data);
270 }
271}
272
273static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
274{
275 struct list_head *p;
276
277 list_for_each(p, &cmd_list) {
278 struct pending_cmd *cmd;
279
280 cmd = list_entry(p, struct pending_cmd, list);
281
282 if (cmd->opcode != opcode)
283 continue;
284
285 if (index >= 0 && cmd->index != index)
286 continue;
287
288 return cmd;
289 }
290
291 return NULL;
292}
293
Johan Hedberga664b5b2011-02-19 12:06:02 -0300294static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200295{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296 list_del(&cmd->list);
297 mgmt_pending_free(cmd);
298}
299
Szymon Janc4e51eae2011-02-25 19:05:48 +0100300static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200302 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300304 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
307 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100311 if (len != sizeof(*cp))
312 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
313
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317
318 hci_dev_lock_bh(hdev);
319
320 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200321 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200323 goto failed;
324 }
325
Szymon Janc4e51eae2011-02-25 19:05:48 +0100326 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
327 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
329 }
330
Szymon Janc4e51eae2011-02-25 19:05:48 +0100331 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300332 if (!cmd) {
333 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
Johan Hedberg72a734e2010-12-30 00:38:22 +0200337 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 queue_work(hdev->workqueue, &hdev->power_on);
339 else
340 queue_work(hdev->workqueue, &hdev->power_off);
341
Johan Hedberg366a0332011-02-19 12:05:55 -0300342 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
344failed:
345 hci_dev_unlock_bh(hdev);
346 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300347 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348}
349
Szymon Janc4e51eae2011-02-25 19:05:48 +0100350static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
351 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200353 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300355 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 u8 scan;
357 int err;
358
359 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100363 if (len != sizeof(*cp))
364 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369
370 hci_dev_lock_bh(hdev);
371
372 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374 goto failed;
375 }
376
Szymon Janc4e51eae2011-02-25 19:05:48 +0100377 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
378 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
379 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 goto failed;
381 }
382
Johan Hedberg72a734e2010-12-30 00:38:22 +0200383 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200384 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100385 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 goto failed;
387 }
388
Szymon Janc4e51eae2011-02-25 19:05:48 +0100389 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300390 if (!cmd) {
391 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200392 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300393 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394
395 scan = SCAN_PAGE;
396
Johan Hedberg72a734e2010-12-30 00:38:22 +0200397 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398 scan |= SCAN_INQUIRY;
399
400 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
401 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300402 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
404failed:
405 hci_dev_unlock_bh(hdev);
406 hci_dev_put(hdev);
407
408 return err;
409}
410
Szymon Janc4e51eae2011-02-25 19:05:48 +0100411static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
412 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200414 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300416 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417 u8 scan;
418 int err;
419
420 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Janc4e51eae2011-02-25 19:05:48 +0100422 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100424 if (len != sizeof(*cp))
425 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
426
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
431 hci_dev_lock_bh(hdev);
432
433 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 goto failed;
436 }
437
Szymon Janc4e51eae2011-02-25 19:05:48 +0100438 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
439 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
440 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200441 goto failed;
442 }
443
Johan Hedberg72a734e2010-12-30 00:38:22 +0200444 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
447 }
448
Szymon Janc4e51eae2011-02-25 19:05:48 +0100449 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300450 if (!cmd) {
451 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300453 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454
Johan Hedberg72a734e2010-12-30 00:38:22 +0200455 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456 scan = SCAN_PAGE;
457 else
458 scan = 0;
459
460 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
461 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300462 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463
464failed:
465 hci_dev_unlock_bh(hdev);
466 hci_dev_put(hdev);
467
468 return err;
469}
470
Szymon Janc4e51eae2011-02-25 19:05:48 +0100471static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
472 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200473{
474 struct sk_buff *skb;
475 struct mgmt_hdr *hdr;
476
477 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
478 if (!skb)
479 return -ENOMEM;
480
481 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
482
483 hdr = (void *) skb_put(skb, sizeof(*hdr));
484 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100485 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200486 hdr->len = cpu_to_le16(data_len);
487
Szymon Janc4e51eae2011-02-25 19:05:48 +0100488 if (data)
489 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200490
491 hci_send_to_sock(NULL, skb, skip_sk);
492 kfree_skb(skb);
493
494 return 0;
495}
496
Johan Hedberg053f0212011-01-26 13:07:10 +0200497static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
498{
Johan Hedberga38528f2011-01-22 06:46:43 +0200499 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200500
Johan Hedberga38528f2011-01-22 06:46:43 +0200501 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200502
Szymon Janc4e51eae2011-02-25 19:05:48 +0100503 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200504}
505
Szymon Janc4e51eae2011-02-25 19:05:48 +0100506static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
507 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200508{
509 struct mgmt_mode *cp, ev;
510 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200511 int err;
512
513 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200514
Szymon Janc4e51eae2011-02-25 19:05:48 +0100515 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200516
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100517 if (len != sizeof(*cp))
518 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
524 hci_dev_lock_bh(hdev);
525
526 if (cp->val)
527 set_bit(HCI_PAIRABLE, &hdev->flags);
528 else
529 clear_bit(HCI_PAIRABLE, &hdev->flags);
530
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532 if (err < 0)
533 goto failed;
534
Johan Hedbergc542a062011-01-26 13:11:03 +0200535 ev.val = cp->val;
536
Szymon Janc4e51eae2011-02-25 19:05:48 +0100537 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200538
539failed:
540 hci_dev_unlock_bh(hdev);
541 hci_dev_put(hdev);
542
543 return err;
544}
545
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200546static u8 get_service_classes(struct hci_dev *hdev)
547{
548 struct list_head *p;
549 u8 val = 0;
550
551 list_for_each(p, &hdev->uuids) {
552 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
553
554 val |= uuid->svc_hint;
555 }
556
557 return val;
558}
559
560static int update_class(struct hci_dev *hdev)
561{
562 u8 cod[3];
563
564 BT_DBG("%s", hdev->name);
565
566 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
567 return 0;
568
569 cod[0] = hdev->minor_class;
570 cod[1] = hdev->major_class;
571 cod[2] = get_service_classes(hdev);
572
573 if (memcmp(cod, hdev->dev_class, 3) == 0)
574 return 0;
575
576 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
577}
578
Szymon Janc4e51eae2011-02-25 19:05:48 +0100579static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200580{
581 struct mgmt_cp_add_uuid *cp;
582 struct hci_dev *hdev;
583 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200584 int err;
585
586 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200587
Szymon Janc4e51eae2011-02-25 19:05:48 +0100588 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200589
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100590 if (len != sizeof(*cp))
591 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
592
Szymon Janc4e51eae2011-02-25 19:05:48 +0100593 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200594 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100595 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200596
597 hci_dev_lock_bh(hdev);
598
599 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
600 if (!uuid) {
601 err = -ENOMEM;
602 goto failed;
603 }
604
605 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200606 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200607
608 list_add(&uuid->list, &hdev->uuids);
609
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200610 err = update_class(hdev);
611 if (err < 0)
612 goto failed;
613
Szymon Janc4e51eae2011-02-25 19:05:48 +0100614 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200615
616failed:
617 hci_dev_unlock_bh(hdev);
618 hci_dev_put(hdev);
619
620 return err;
621}
622
Szymon Janc4e51eae2011-02-25 19:05:48 +0100623static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200624{
625 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100626 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200627 struct hci_dev *hdev;
628 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 +0200629 int err, found;
630
631 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200632
Szymon Janc4e51eae2011-02-25 19:05:48 +0100633 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200634
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100635 if (len != sizeof(*cp))
636 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
637
Szymon Janc4e51eae2011-02-25 19:05:48 +0100638 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200639 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100640 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200641
642 hci_dev_lock_bh(hdev);
643
644 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
645 err = hci_uuids_clear(hdev);
646 goto unlock;
647 }
648
649 found = 0;
650
651 list_for_each_safe(p, n, &hdev->uuids) {
652 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
653
654 if (memcmp(match->uuid, cp->uuid, 16) != 0)
655 continue;
656
657 list_del(&match->list);
658 found++;
659 }
660
661 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100662 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200663 goto unlock;
664 }
665
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200666 err = update_class(hdev);
667 if (err < 0)
668 goto unlock;
669
Szymon Janc4e51eae2011-02-25 19:05:48 +0100670 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200671
672unlock:
673 hci_dev_unlock_bh(hdev);
674 hci_dev_put(hdev);
675
676 return err;
677}
678
Szymon Janc4e51eae2011-02-25 19:05:48 +0100679static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
680 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200681{
682 struct hci_dev *hdev;
683 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200684 int err;
685
686 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200687
Szymon Janc4e51eae2011-02-25 19:05:48 +0100688 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200689
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100690 if (len != sizeof(*cp))
691 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
692
Szymon Janc4e51eae2011-02-25 19:05:48 +0100693 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200694 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100695 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696
697 hci_dev_lock_bh(hdev);
698
699 hdev->major_class = cp->major;
700 hdev->minor_class = cp->minor;
701
702 err = update_class(hdev);
703
704 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100705 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200706
707 hci_dev_unlock_bh(hdev);
708 hci_dev_put(hdev);
709
710 return err;
711}
712
Szymon Janc4e51eae2011-02-25 19:05:48 +0100713static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
714 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200715{
716 struct hci_dev *hdev;
717 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200718 int err;
719
720 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200721
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100722 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100723 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100724
Szymon Janc4e51eae2011-02-25 19:05:48 +0100725 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200726 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100727 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200728
729 hci_dev_lock_bh(hdev);
730
Szymon Janc4e51eae2011-02-25 19:05:48 +0100731 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200732
733 if (cp->enable) {
734 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
735 err = 0;
736 } else {
737 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
738 err = update_class(hdev);
739 }
740
741 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
743 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200744
745 hci_dev_unlock_bh(hdev);
746 hci_dev_put(hdev);
747
748 return err;
749}
750
Szymon Janc4e51eae2011-02-25 19:05:48 +0100751static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200752{
753 struct hci_dev *hdev;
754 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100755 u16 key_count, expected_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200756 int i;
757
758 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100759
760 if (len < sizeof(*cp))
761 return -EINVAL;
762
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200763 key_count = get_unaligned_le16(&cp->key_count);
764
765 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
766 if (expected_len != len) {
767 BT_ERR("load_keys: expected %u bytes, got %u bytes",
768 len, expected_len);
769 return -EINVAL;
770 }
771
Szymon Janc4e51eae2011-02-25 19:05:48 +0100772 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200773 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100774 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200775
Szymon Janc4e51eae2011-02-25 19:05:48 +0100776 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200777 key_count);
778
779 hci_dev_lock_bh(hdev);
780
781 hci_link_keys_clear(hdev);
782
783 set_bit(HCI_LINK_KEYS, &hdev->flags);
784
785 if (cp->debug_keys)
786 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
787 else
788 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
789
790 for (i = 0; i < key_count; i++) {
791 struct mgmt_key_info *key = &cp->keys[i];
792
793 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
794 key->pin_len);
795 }
796
797 hci_dev_unlock_bh(hdev);
798 hci_dev_put(hdev);
799
800 return 0;
801}
802
Szymon Janc4e51eae2011-02-25 19:05:48 +0100803static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200804{
805 struct hci_dev *hdev;
806 struct mgmt_cp_remove_key *cp;
807 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200808 int err;
809
810 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200811
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100812 if (len != sizeof(*cp))
813 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
814
Szymon Janc4e51eae2011-02-25 19:05:48 +0100815 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200816 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100817 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200818
819 hci_dev_lock_bh(hdev);
820
821 err = hci_remove_link_key(hdev, &cp->bdaddr);
822 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100823 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200824 goto unlock;
825 }
826
827 err = 0;
828
829 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
830 goto unlock;
831
832 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
833 if (conn) {
834 struct hci_cp_disconnect dc;
835
836 put_unaligned_le16(conn->handle, &dc.handle);
837 dc.reason = 0x13; /* Remote User Terminated Connection */
838 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
839 }
840
841unlock:
842 hci_dev_unlock_bh(hdev);
843 hci_dev_put(hdev);
844
845 return err;
846}
847
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200849{
850 struct hci_dev *hdev;
851 struct mgmt_cp_disconnect *cp;
852 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300853 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200854 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200855 int err;
856
857 BT_DBG("");
858
859 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200860
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100861 if (len != sizeof(*cp))
862 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
863
Szymon Janc4e51eae2011-02-25 19:05:48 +0100864 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200865 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200867
868 hci_dev_lock_bh(hdev);
869
870 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200872 goto failed;
873 }
874
Szymon Janc4e51eae2011-02-25 19:05:48 +0100875 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
876 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200877 goto failed;
878 }
879
880 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
881 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200883 goto failed;
884 }
885
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300887 if (!cmd) {
888 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200889 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300890 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200891
892 put_unaligned_le16(conn->handle, &dc.handle);
893 dc.reason = 0x13; /* Remote User Terminated Connection */
894
895 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
896 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300897 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200898
899failed:
900 hci_dev_unlock_bh(hdev);
901 hci_dev_put(hdev);
902
903 return err;
904}
905
Szymon Janc8ce62842011-03-01 16:55:32 +0100906static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200907{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200908 struct mgmt_rp_get_connections *rp;
909 struct hci_dev *hdev;
910 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200911 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100912 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200913 int i, err;
914
915 BT_DBG("");
916
Szymon Janc4e51eae2011-02-25 19:05:48 +0100917 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200918 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100919 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200920
921 hci_dev_lock_bh(hdev);
922
923 count = 0;
924 list_for_each(p, &hdev->conn_hash.list) {
925 count++;
926 }
927
Johan Hedberga38528f2011-01-22 06:46:43 +0200928 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
929 rp = kmalloc(rp_len, GFP_ATOMIC);
930 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200931 err = -ENOMEM;
932 goto unlock;
933 }
934
Johan Hedberg2784eb42011-01-21 13:56:35 +0200935 put_unaligned_le16(count, &rp->conn_count);
936
937 read_lock(&hci_dev_list_lock);
938
939 i = 0;
940 list_for_each(p, &hdev->conn_hash.list) {
941 struct hci_conn *c = list_entry(p, struct hci_conn, list);
942
943 bacpy(&rp->conn[i++], &c->dst);
944 }
945
946 read_unlock(&hci_dev_list_lock);
947
Szymon Janc4e51eae2011-02-25 19:05:48 +0100948 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200949
950unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200951 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200952 hci_dev_unlock_bh(hdev);
953 hci_dev_put(hdev);
954 return err;
955}
956
Szymon Janc4e51eae2011-02-25 19:05:48 +0100957static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
958 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200959{
960 struct hci_dev *hdev;
961 struct mgmt_cp_pin_code_reply *cp;
962 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300963 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200964 int err;
965
966 BT_DBG("");
967
968 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200969
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100970 if (len != sizeof(*cp))
971 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
972
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200974 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200976
977 hci_dev_lock_bh(hdev);
978
979 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200981 goto failed;
982 }
983
Szymon Janc4e51eae2011-02-25 19:05:48 +0100984 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300985 if (!cmd) {
986 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200987 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300988 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200989
990 bacpy(&reply.bdaddr, &cp->bdaddr);
991 reply.pin_len = cp->pin_len;
992 memcpy(reply.pin_code, cp->pin_code, 16);
993
994 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
995 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300996 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200997
998failed:
999 hci_dev_unlock_bh(hdev);
1000 hci_dev_put(hdev);
1001
1002 return err;
1003}
1004
Szymon Janc4e51eae2011-02-25 19:05:48 +01001005static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1006 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001007{
1008 struct hci_dev *hdev;
1009 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001010 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001011 int err;
1012
1013 BT_DBG("");
1014
1015 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001016
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001017 if (len != sizeof(*cp))
1018 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1019 EINVAL);
1020
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001022 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1024 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001025
1026 hci_dev_lock_bh(hdev);
1027
1028 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1030 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001031 goto failed;
1032 }
1033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001035 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001036 if (!cmd) {
1037 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001038 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001039 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001040
Szymon Janc3cf2a4f2011-03-01 16:55:33 +01001041 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
Johan Hedberg980e1a52011-01-22 06:10:07 +02001042 &cp->bdaddr);
1043 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001044 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001045
1046failed:
1047 hci_dev_unlock_bh(hdev);
1048 hci_dev_put(hdev);
1049
1050 return err;
1051}
1052
Szymon Janc4e51eae2011-02-25 19:05:48 +01001053static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1054 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001055{
1056 struct hci_dev *hdev;
1057 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001058
1059 BT_DBG("");
1060
1061 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001062
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001063 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001064 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001065
Szymon Janc4e51eae2011-02-25 19:05:48 +01001066 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001067 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001068 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001069
1070 hci_dev_lock_bh(hdev);
1071
1072 hdev->io_capability = cp->io_capability;
1073
1074 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001075 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001076
1077 hci_dev_unlock_bh(hdev);
1078 hci_dev_put(hdev);
1079
Szymon Janc4e51eae2011-02-25 19:05:48 +01001080 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001081}
1082
Johan Hedberge9a416b2011-02-19 12:05:56 -03001083static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1084{
1085 struct hci_dev *hdev = conn->hdev;
1086 struct list_head *p;
1087
1088 list_for_each(p, &cmd_list) {
1089 struct pending_cmd *cmd;
1090
1091 cmd = list_entry(p, struct pending_cmd, list);
1092
1093 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1094 continue;
1095
1096 if (cmd->index != hdev->id)
1097 continue;
1098
1099 if (cmd->user_data != conn)
1100 continue;
1101
1102 return cmd;
1103 }
1104
1105 return NULL;
1106}
1107
1108static void pairing_complete(struct pending_cmd *cmd, u8 status)
1109{
1110 struct mgmt_rp_pair_device rp;
1111 struct hci_conn *conn = cmd->user_data;
1112
Johan Hedberge9a416b2011-02-19 12:05:56 -03001113 bacpy(&rp.bdaddr, &conn->dst);
1114 rp.status = status;
1115
Szymon Janc4e51eae2011-02-25 19:05:48 +01001116 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001117
1118 /* So we don't get further callbacks for this connection */
1119 conn->connect_cfm_cb = NULL;
1120 conn->security_cfm_cb = NULL;
1121 conn->disconn_cfm_cb = NULL;
1122
1123 hci_conn_put(conn);
1124
Johan Hedberga664b5b2011-02-19 12:06:02 -03001125 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001126}
1127
1128static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1129{
1130 struct pending_cmd *cmd;
1131
1132 BT_DBG("status %u", status);
1133
1134 cmd = find_pairing(conn);
1135 if (!cmd) {
1136 BT_DBG("Unable to find a pending command");
1137 return;
1138 }
1139
1140 pairing_complete(cmd, status);
1141}
1142
Szymon Janc4e51eae2011-02-25 19:05:48 +01001143static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001144{
1145 struct hci_dev *hdev;
1146 struct mgmt_cp_pair_device *cp;
1147 struct pending_cmd *cmd;
1148 u8 sec_level, auth_type;
1149 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001150 int err;
1151
1152 BT_DBG("");
1153
1154 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001155
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001156 if (len != sizeof(*cp))
1157 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1158
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001160 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001161 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001162
1163 hci_dev_lock_bh(hdev);
1164
1165 if (cp->io_cap == 0x03) {
1166 sec_level = BT_SECURITY_MEDIUM;
1167 auth_type = HCI_AT_DEDICATED_BONDING;
1168 } else {
1169 sec_level = BT_SECURITY_HIGH;
1170 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1171 }
1172
1173 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001174 if (IS_ERR(conn)) {
1175 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001176 goto unlock;
1177 }
1178
1179 if (conn->connect_cfm_cb) {
1180 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001182 goto unlock;
1183 }
1184
Szymon Janc4e51eae2011-02-25 19:05:48 +01001185 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001186 if (!cmd) {
1187 err = -ENOMEM;
1188 hci_conn_put(conn);
1189 goto unlock;
1190 }
1191
1192 conn->connect_cfm_cb = pairing_complete_cb;
1193 conn->security_cfm_cb = pairing_complete_cb;
1194 conn->disconn_cfm_cb = pairing_complete_cb;
1195 conn->io_capability = cp->io_cap;
1196 cmd->user_data = conn;
1197
1198 if (conn->state == BT_CONNECTED &&
1199 hci_conn_security(conn, sec_level, auth_type))
1200 pairing_complete(cmd, 0);
1201
1202 err = 0;
1203
1204unlock:
1205 hci_dev_unlock_bh(hdev);
1206 hci_dev_put(hdev);
1207
1208 return err;
1209}
1210
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1212 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001213{
1214 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001216 struct pending_cmd *cmd;
1217 struct hci_dev *hdev;
1218 int err;
1219
1220 BT_DBG("");
1221
Johan Hedberga5c29682011-02-19 12:05:57 -03001222 if (success) {
1223 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1224 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1225 } else {
1226 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1227 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1228 }
1229
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001230 if (len != sizeof(*cp))
1231 return cmd_status(sk, index, mgmt_op, EINVAL);
1232
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001234 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001236
1237 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001239 goto failed;
1240 }
1241
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001243 if (!cmd) {
1244 err = -ENOMEM;
1245 goto failed;
1246 }
1247
1248 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001249 if (err < 0)
1250 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001251
1252failed:
1253 hci_dev_unlock_bh(hdev);
1254 hci_dev_put(hdev);
1255
1256 return err;
1257}
1258
Johan Hedberg03811012010-12-08 00:21:06 +02001259int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1260{
1261 unsigned char *buf;
1262 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001264 int err;
1265
1266 BT_DBG("got %zu bytes", msglen);
1267
1268 if (msglen < sizeof(*hdr))
1269 return -EINVAL;
1270
1271 buf = kmalloc(msglen, GFP_ATOMIC);
1272 if (!buf)
1273 return -ENOMEM;
1274
1275 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1276 err = -EFAULT;
1277 goto done;
1278 }
1279
1280 hdr = (struct mgmt_hdr *) buf;
1281 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001282 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001283 len = get_unaligned_le16(&hdr->len);
1284
1285 if (len != msglen - sizeof(*hdr)) {
1286 err = -EINVAL;
1287 goto done;
1288 }
1289
1290 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001291 case MGMT_OP_READ_VERSION:
1292 err = read_version(sk);
1293 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001294 case MGMT_OP_READ_INDEX_LIST:
1295 err = read_index_list(sk);
1296 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001297 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001299 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001300 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001302 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001303 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001304 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001305 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001306 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001308 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001309 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001311 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001313 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314 break;
1315 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001316 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001317 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001318 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001320 break;
1321 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001322 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001323 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001324 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001326 break;
1327 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001328 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001329 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001330 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001331 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001332 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001333 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001334 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001335 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338 break;
1339 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001342 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001344 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001348 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001350 break;
1351 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001353 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001354 default:
1355 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001356 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001357 break;
1358 }
1359
Johan Hedberge41d8b42010-12-13 21:07:03 +02001360 if (err < 0)
1361 goto done;
1362
Johan Hedberg03811012010-12-08 00:21:06 +02001363 err = msglen;
1364
1365done:
1366 kfree(buf);
1367 return err;
1368}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001369
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001370int mgmt_index_added(u16 index)
1371{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001372 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001373}
1374
1375int mgmt_index_removed(u16 index)
1376{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001377 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001378}
1379
Johan Hedberg73f22f62010-12-29 16:00:25 +02001380struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001381 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001382 struct sock *sk;
1383};
1384
Johan Hedberg72a734e2010-12-30 00:38:22 +02001385static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001386{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001387 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001388 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389
Johan Hedberg72a734e2010-12-30 00:38:22 +02001390 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001391 return;
1392
Johan Hedberg053f0212011-01-26 13:07:10 +02001393 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001394
1395 list_del(&cmd->list);
1396
1397 if (match->sk == NULL) {
1398 match->sk = cmd->sk;
1399 sock_hold(match->sk);
1400 }
1401
1402 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001403}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001404
1405int mgmt_powered(u16 index, u8 powered)
1406{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001407 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001408 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001409 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001410
Johan Hedberg72a734e2010-12-30 00:38:22 +02001411 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001412
Johan Hedberg72a734e2010-12-30 00:38:22 +02001413 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001416
1417 if (match.sk)
1418 sock_put(match.sk);
1419
1420 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001421}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422
Johan Hedberg73f22f62010-12-29 16:00:25 +02001423int mgmt_discoverable(u16 index, u8 discoverable)
1424{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001425 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001426 struct cmd_lookup match = { discoverable, NULL };
1427 int ret;
1428
Szymon Jancb8534e02011-03-01 16:55:34 +01001429 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001430
Johan Hedberg72a734e2010-12-30 00:38:22 +02001431 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001432
Szymon Janc4e51eae2011-02-25 19:05:48 +01001433 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1434 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001435
1436 if (match.sk)
1437 sock_put(match.sk);
1438
1439 return ret;
1440}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001441
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001442int mgmt_connectable(u16 index, u8 connectable)
1443{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001444 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001445 struct cmd_lookup match = { connectable, NULL };
1446 int ret;
1447
Johan Hedberg72a734e2010-12-30 00:38:22 +02001448 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001449
Johan Hedberg72a734e2010-12-30 00:38:22 +02001450 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001453
1454 if (match.sk)
1455 sock_put(match.sk);
1456
1457 return ret;
1458}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001459
1460int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1461{
1462 struct mgmt_ev_new_key ev;
1463
1464 memset(&ev, 0, sizeof(ev));
1465
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001466 bacpy(&ev.key.bdaddr, &key->bdaddr);
1467 ev.key.type = key->type;
1468 memcpy(ev.key.val, key->val, 16);
1469 ev.key.pin_len = key->pin_len;
1470 ev.old_key_type = old_key_type;
1471
Szymon Janc4e51eae2011-02-25 19:05:48 +01001472 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001473}
Johan Hedbergf7520542011-01-20 12:34:39 +02001474
1475int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1476{
1477 struct mgmt_ev_connected ev;
1478
Johan Hedbergf7520542011-01-20 12:34:39 +02001479 bacpy(&ev.bdaddr, bdaddr);
1480
Szymon Janc4e51eae2011-02-25 19:05:48 +01001481 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001482}
1483
Johan Hedberg8962ee72011-01-20 12:40:27 +02001484static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1485{
1486 struct mgmt_cp_disconnect *cp = cmd->cmd;
1487 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001488 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489
Johan Hedberga38528f2011-01-22 06:46:43 +02001490 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491
Szymon Janc4e51eae2011-02-25 19:05:48 +01001492 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001493
1494 *sk = cmd->sk;
1495 sock_hold(*sk);
1496
Johan Hedberga664b5b2011-02-19 12:06:02 -03001497 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001498}
1499
Johan Hedbergf7520542011-01-20 12:34:39 +02001500int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1501{
1502 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001503 struct sock *sk = NULL;
1504 int err;
1505
1506 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001507
Johan Hedbergf7520542011-01-20 12:34:39 +02001508 bacpy(&ev.bdaddr, bdaddr);
1509
Szymon Janc4e51eae2011-02-25 19:05:48 +01001510 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001511
1512 if (sk)
1513 sock_put(sk);
1514
1515 return err;
1516}
1517
1518int mgmt_disconnect_failed(u16 index)
1519{
1520 struct pending_cmd *cmd;
1521 int err;
1522
1523 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1524 if (!cmd)
1525 return -ENOENT;
1526
Szymon Janc4e51eae2011-02-25 19:05:48 +01001527 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001528
Johan Hedberga664b5b2011-02-19 12:06:02 -03001529 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001530
1531 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001532}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001533
1534int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1535{
1536 struct mgmt_ev_connect_failed ev;
1537
Johan Hedberg17d5c042011-01-22 06:09:08 +02001538 bacpy(&ev.bdaddr, bdaddr);
1539 ev.status = status;
1540
Szymon Janc4e51eae2011-02-25 19:05:48 +01001541 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001542}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001543
1544int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1545{
1546 struct mgmt_ev_pin_code_request ev;
1547
Johan Hedberg980e1a52011-01-22 06:10:07 +02001548 bacpy(&ev.bdaddr, bdaddr);
1549
Szymon Janc4e51eae2011-02-25 19:05:48 +01001550 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1551 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001552}
1553
1554int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1555{
1556 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001557 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001558 int err;
1559
1560 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1561 if (!cmd)
1562 return -ENOENT;
1563
Johan Hedbergac56fb12011-02-19 12:05:59 -03001564 bacpy(&rp.bdaddr, bdaddr);
1565 rp.status = status;
1566
Szymon Janc4e51eae2011-02-25 19:05:48 +01001567 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1568 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001569
Johan Hedberga664b5b2011-02-19 12:06:02 -03001570 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001571
1572 return err;
1573}
1574
1575int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1576{
1577 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001578 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001579 int err;
1580
1581 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1582 if (!cmd)
1583 return -ENOENT;
1584
Johan Hedbergac56fb12011-02-19 12:05:59 -03001585 bacpy(&rp.bdaddr, bdaddr);
1586 rp.status = status;
1587
Szymon Janc4e51eae2011-02-25 19:05:48 +01001588 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1589 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001590
Johan Hedberga664b5b2011-02-19 12:06:02 -03001591 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001592
1593 return err;
1594}
Johan Hedberga5c29682011-02-19 12:05:57 -03001595
1596int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1597{
1598 struct mgmt_ev_user_confirm_request ev;
1599
1600 BT_DBG("hci%u", index);
1601
Johan Hedberga5c29682011-02-19 12:05:57 -03001602 bacpy(&ev.bdaddr, bdaddr);
1603 put_unaligned_le32(value, &ev.value);
1604
Szymon Janc4e51eae2011-02-25 19:05:48 +01001605 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1606 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001607}
1608
1609static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1610 u8 opcode)
1611{
1612 struct pending_cmd *cmd;
1613 struct mgmt_rp_user_confirm_reply rp;
1614 int err;
1615
1616 cmd = mgmt_pending_find(opcode, index);
1617 if (!cmd)
1618 return -ENOENT;
1619
Johan Hedberga5c29682011-02-19 12:05:57 -03001620 bacpy(&rp.bdaddr, bdaddr);
1621 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001622 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001623
Johan Hedberga664b5b2011-02-19 12:06:02 -03001624 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001625
1626 return err;
1627}
1628
1629int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1630{
1631 return confirm_reply_complete(index, bdaddr, status,
1632 MGMT_OP_USER_CONFIRM_REPLY);
1633}
1634
Szymon Jancb8534e02011-03-01 16:55:34 +01001635int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001636{
1637 return confirm_reply_complete(index, bdaddr, status,
1638 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1639}
Johan Hedberg2a611692011-02-19 12:06:00 -03001640
1641int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1642{
1643 struct mgmt_ev_auth_failed ev;
1644
Johan Hedberg2a611692011-02-19 12:06:00 -03001645 bacpy(&ev.bdaddr, bdaddr);
1646 ev.status = status;
1647
Szymon Janc4e51eae2011-02-25 19:05:48 +01001648 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001649}