blob: f7ce78235590496a60533d25765e945fc727d38c [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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200804{
805 struct hci_dev *hdev;
806 struct mgmt_cp_remove_key *cp;
807 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200808 int err;
809
810 cp = (void *) data;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedbergb312b1612011-03-16 14:29:37 +02001259static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1260 u16 len)
1261{
1262 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1263 struct hci_cp_write_local_name hci_cp;
1264 struct hci_dev *hdev;
1265 struct pending_cmd *cmd;
1266 int err;
1267
1268 BT_DBG("");
1269
1270 if (len != sizeof(*mgmt_cp))
1271 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1272
1273 hdev = hci_dev_get(index);
1274 if (!hdev)
1275 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1276
1277 hci_dev_lock_bh(hdev);
1278
1279 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1280 if (!cmd) {
1281 err = -ENOMEM;
1282 goto failed;
1283 }
1284
1285 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1286 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1287 &hci_cp);
1288 if (err < 0)
1289 mgmt_pending_remove(cmd);
1290
1291failed:
1292 hci_dev_unlock_bh(hdev);
1293 hci_dev_put(hdev);
1294
1295 return err;
1296}
1297
Johan Hedberg03811012010-12-08 00:21:06 +02001298int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1299{
1300 unsigned char *buf;
1301 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001302 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001303 int err;
1304
1305 BT_DBG("got %zu bytes", msglen);
1306
1307 if (msglen < sizeof(*hdr))
1308 return -EINVAL;
1309
1310 buf = kmalloc(msglen, GFP_ATOMIC);
1311 if (!buf)
1312 return -ENOMEM;
1313
1314 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1315 err = -EFAULT;
1316 goto done;
1317 }
1318
1319 hdr = (struct mgmt_hdr *) buf;
1320 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001322 len = get_unaligned_le16(&hdr->len);
1323
1324 if (len != msglen - sizeof(*hdr)) {
1325 err = -EINVAL;
1326 goto done;
1327 }
1328
1329 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001330 case MGMT_OP_READ_VERSION:
1331 err = read_version(sk);
1332 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001333 case MGMT_OP_READ_INDEX_LIST:
1334 err = read_index_list(sk);
1335 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001336 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001338 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001339 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001341 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001342 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001344 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001345 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001347 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001348 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001350 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353 break;
1354 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001355 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001356 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001357 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001358 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001359 break;
1360 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001361 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001362 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001363 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001365 break;
1366 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001368 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001369 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001370 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001371 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001372 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001373 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001374 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001375 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001376 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001377 break;
1378 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001379 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001381 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001382 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001383 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001385 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001386 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001387 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001388 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001389 break;
1390 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001392 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001393 case MGMT_OP_SET_LOCAL_NAME:
1394 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1395 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001396 default:
1397 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001399 break;
1400 }
1401
Johan Hedberge41d8b42010-12-13 21:07:03 +02001402 if (err < 0)
1403 goto done;
1404
Johan Hedberg03811012010-12-08 00:21:06 +02001405 err = msglen;
1406
1407done:
1408 kfree(buf);
1409 return err;
1410}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001411
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001412int mgmt_index_added(u16 index)
1413{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001414 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001415}
1416
1417int mgmt_index_removed(u16 index)
1418{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001420}
1421
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001423 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001424 struct sock *sk;
1425};
1426
Johan Hedberg72a734e2010-12-30 00:38:22 +02001427static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001428{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001429 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001430 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001431
Johan Hedberg72a734e2010-12-30 00:38:22 +02001432 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001433 return;
1434
Johan Hedberg053f0212011-01-26 13:07:10 +02001435 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001436
1437 list_del(&cmd->list);
1438
1439 if (match->sk == NULL) {
1440 match->sk = cmd->sk;
1441 sock_hold(match->sk);
1442 }
1443
1444 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001445}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001446
1447int mgmt_powered(u16 index, u8 powered)
1448{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001449 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001450 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001451 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001452
Johan Hedberg72a734e2010-12-30 00:38:22 +02001453 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001454
Johan Hedberg72a734e2010-12-30 00:38:22 +02001455 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001456
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001458
1459 if (match.sk)
1460 sock_put(match.sk);
1461
1462 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001463}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001464
Johan Hedberg73f22f62010-12-29 16:00:25 +02001465int mgmt_discoverable(u16 index, u8 discoverable)
1466{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001467 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001468 struct cmd_lookup match = { discoverable, NULL };
1469 int ret;
1470
Szymon Jancb8534e02011-03-01 16:55:34 +01001471 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001472
Johan Hedberg72a734e2010-12-30 00:38:22 +02001473 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001474
Szymon Janc4e51eae2011-02-25 19:05:48 +01001475 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1476 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001477
1478 if (match.sk)
1479 sock_put(match.sk);
1480
1481 return ret;
1482}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001483
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001484int mgmt_connectable(u16 index, u8 connectable)
1485{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001486 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001487 struct cmd_lookup match = { connectable, NULL };
1488 int ret;
1489
Johan Hedberg72a734e2010-12-30 00:38:22 +02001490 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001491
Johan Hedberg72a734e2010-12-30 00:38:22 +02001492 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001493
Szymon Janc4e51eae2011-02-25 19:05:48 +01001494 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001495
1496 if (match.sk)
1497 sock_put(match.sk);
1498
1499 return ret;
1500}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501
1502int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1503{
1504 struct mgmt_ev_new_key ev;
1505
1506 memset(&ev, 0, sizeof(ev));
1507
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 bacpy(&ev.key.bdaddr, &key->bdaddr);
1509 ev.key.type = key->type;
1510 memcpy(ev.key.val, key->val, 16);
1511 ev.key.pin_len = key->pin_len;
1512 ev.old_key_type = old_key_type;
1513
Szymon Janc4e51eae2011-02-25 19:05:48 +01001514 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001515}
Johan Hedbergf7520542011-01-20 12:34:39 +02001516
1517int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1518{
1519 struct mgmt_ev_connected ev;
1520
Johan Hedbergf7520542011-01-20 12:34:39 +02001521 bacpy(&ev.bdaddr, bdaddr);
1522
Szymon Janc4e51eae2011-02-25 19:05:48 +01001523 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001524}
1525
Johan Hedberg8962ee72011-01-20 12:40:27 +02001526static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1527{
1528 struct mgmt_cp_disconnect *cp = cmd->cmd;
1529 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001530 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001531
Johan Hedberga38528f2011-01-22 06:46:43 +02001532 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001533
Szymon Janc4e51eae2011-02-25 19:05:48 +01001534 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001535
1536 *sk = cmd->sk;
1537 sock_hold(*sk);
1538
Johan Hedberga664b5b2011-02-19 12:06:02 -03001539 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001540}
1541
Johan Hedbergf7520542011-01-20 12:34:39 +02001542int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1543{
1544 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001545 struct sock *sk = NULL;
1546 int err;
1547
1548 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001549
Johan Hedbergf7520542011-01-20 12:34:39 +02001550 bacpy(&ev.bdaddr, bdaddr);
1551
Szymon Janc4e51eae2011-02-25 19:05:48 +01001552 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001553
1554 if (sk)
1555 sock_put(sk);
1556
1557 return err;
1558}
1559
1560int mgmt_disconnect_failed(u16 index)
1561{
1562 struct pending_cmd *cmd;
1563 int err;
1564
1565 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1566 if (!cmd)
1567 return -ENOENT;
1568
Szymon Janc4e51eae2011-02-25 19:05:48 +01001569 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001570
Johan Hedberga664b5b2011-02-19 12:06:02 -03001571 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001572
1573 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001574}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001575
1576int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1577{
1578 struct mgmt_ev_connect_failed ev;
1579
Johan Hedberg17d5c042011-01-22 06:09:08 +02001580 bacpy(&ev.bdaddr, bdaddr);
1581 ev.status = status;
1582
Szymon Janc4e51eae2011-02-25 19:05:48 +01001583 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001584}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001585
1586int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1587{
1588 struct mgmt_ev_pin_code_request ev;
1589
Johan Hedberg980e1a52011-01-22 06:10:07 +02001590 bacpy(&ev.bdaddr, bdaddr);
1591
Szymon Janc4e51eae2011-02-25 19:05:48 +01001592 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1593 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001594}
1595
1596int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1597{
1598 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001599 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001600 int err;
1601
1602 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1603 if (!cmd)
1604 return -ENOENT;
1605
Johan Hedbergac56fb12011-02-19 12:05:59 -03001606 bacpy(&rp.bdaddr, bdaddr);
1607 rp.status = status;
1608
Szymon Janc4e51eae2011-02-25 19:05:48 +01001609 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1610 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001611
Johan Hedberga664b5b2011-02-19 12:06:02 -03001612 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001613
1614 return err;
1615}
1616
1617int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1618{
1619 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001620 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001621 int err;
1622
1623 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1624 if (!cmd)
1625 return -ENOENT;
1626
Johan Hedbergac56fb12011-02-19 12:05:59 -03001627 bacpy(&rp.bdaddr, bdaddr);
1628 rp.status = status;
1629
Szymon Janc4e51eae2011-02-25 19:05:48 +01001630 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1631 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001632
Johan Hedberga664b5b2011-02-19 12:06:02 -03001633 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001634
1635 return err;
1636}
Johan Hedberga5c29682011-02-19 12:05:57 -03001637
1638int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1639{
1640 struct mgmt_ev_user_confirm_request ev;
1641
1642 BT_DBG("hci%u", index);
1643
Johan Hedberga5c29682011-02-19 12:05:57 -03001644 bacpy(&ev.bdaddr, bdaddr);
1645 put_unaligned_le32(value, &ev.value);
1646
Szymon Janc4e51eae2011-02-25 19:05:48 +01001647 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1648 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001649}
1650
1651static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1652 u8 opcode)
1653{
1654 struct pending_cmd *cmd;
1655 struct mgmt_rp_user_confirm_reply rp;
1656 int err;
1657
1658 cmd = mgmt_pending_find(opcode, index);
1659 if (!cmd)
1660 return -ENOENT;
1661
Johan Hedberga5c29682011-02-19 12:05:57 -03001662 bacpy(&rp.bdaddr, bdaddr);
1663 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001664 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001665
Johan Hedberga664b5b2011-02-19 12:06:02 -03001666 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001667
1668 return err;
1669}
1670
1671int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1672{
1673 return confirm_reply_complete(index, bdaddr, status,
1674 MGMT_OP_USER_CONFIRM_REPLY);
1675}
1676
Szymon Jancb8534e02011-03-01 16:55:34 +01001677int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001678{
1679 return confirm_reply_complete(index, bdaddr, status,
1680 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1681}
Johan Hedberg2a611692011-02-19 12:06:00 -03001682
1683int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1684{
1685 struct mgmt_ev_auth_failed ev;
1686
Johan Hedberg2a611692011-02-19 12:06:00 -03001687 bacpy(&ev.bdaddr, bdaddr);
1688 ev.status = status;
1689
Szymon Janc4e51eae2011-02-25 19:05:48 +01001690 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001691}
Johan Hedbergb312b1612011-03-16 14:29:37 +02001692
1693int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
1694{
1695 struct pending_cmd *cmd;
1696 struct mgmt_cp_set_local_name ev;
1697 int err;
1698
1699 memset(&ev, 0, sizeof(ev));
1700 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
1701
1702 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
1703 if (!cmd)
1704 goto send_event;
1705
1706 if (status) {
1707 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
1708 goto failed;
1709 }
1710
1711 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
1712 sizeof(ev));
1713 if (err < 0)
1714 goto failed;
1715
1716send_event:
1717 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
1718 cmd ? cmd->sk : NULL);
1719
1720failed:
1721 if (cmd)
1722 mgmt_pending_remove(cmd);
1723 return err;
1724}