blob: 33b1f7400dab0ac2fc4d374df11de9c656a5634b [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;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 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);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100220 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200221 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
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100236 cmd->param = kmalloc(len, GFP_ATOMIC);
237 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200238 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300239 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200240 }
241
Szymon Janc8fce6352011-03-22 13:12:20 +0100242 if (data)
243 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244
245 cmd->sk = sk;
246 sock_hold(sk);
247
248 list_add(&cmd->list, &cmd_list);
249
Johan Hedberg366a0332011-02-19 12:05:55 -0300250 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200251}
252
253static void mgmt_pending_foreach(u16 opcode, int index,
254 void (*cb)(struct pending_cmd *cmd, void *data),
255 void *data)
256{
257 struct list_head *p, *n;
258
259 list_for_each_safe(p, n, &cmd_list) {
260 struct pending_cmd *cmd;
261
262 cmd = list_entry(p, struct pending_cmd, list);
263
264 if (cmd->opcode != opcode)
265 continue;
266
267 if (index >= 0 && cmd->index != index)
268 continue;
269
270 cb(cmd, data);
271 }
272}
273
274static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
275{
276 struct list_head *p;
277
278 list_for_each(p, &cmd_list) {
279 struct pending_cmd *cmd;
280
281 cmd = list_entry(p, struct pending_cmd, list);
282
283 if (cmd->opcode != opcode)
284 continue;
285
286 if (index >= 0 && cmd->index != index)
287 continue;
288
289 return cmd;
290 }
291
292 return NULL;
293}
294
Johan Hedberga664b5b2011-02-19 12:06:02 -0300295static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297 list_del(&cmd->list);
298 mgmt_pending_free(cmd);
299}
300
Szymon Janc4e51eae2011-02-25 19:05:48 +0100301static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200303 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200307
308 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200309
Szymon Janc4e51eae2011-02-25 19:05:48 +0100310 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100312 if (len != sizeof(*cp))
313 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
314
Szymon Janc4e51eae2011-02-25 19:05:48 +0100315 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100317 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200318
319 hci_dev_lock_bh(hdev);
320
321 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200322 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 goto failed;
325 }
326
Szymon Janc4e51eae2011-02-25 19:05:48 +0100327 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
328 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 goto failed;
330 }
331
Szymon Janc4e51eae2011-02-25 19:05:48 +0100332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 if (!cmd) {
334 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300336 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Johan Hedberg72a734e2010-12-30 00:38:22 +0200338 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 queue_work(hdev->workqueue, &hdev->power_on);
340 else
341 queue_work(hdev->workqueue, &hdev->power_off);
342
Johan Hedberg366a0332011-02-19 12:05:55 -0300343 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344
345failed:
346 hci_dev_unlock_bh(hdev);
347 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200349}
350
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
352 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200354 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300356 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357 u8 scan;
358 int err;
359
360 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100364 if (len != sizeof(*cp))
365 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
366
Szymon Janc4e51eae2011-02-25 19:05:48 +0100367 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200370
371 hci_dev_lock_bh(hdev);
372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200375 goto failed;
376 }
377
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
380 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 goto failed;
382 }
383
Johan Hedberg72a734e2010-12-30 00:38:22 +0200384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387 goto failed;
388 }
389
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 if (!cmd) {
392 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
396 scan = SCAN_PAGE;
397
Johan Hedberg72a734e2010-12-30 00:38:22 +0200398 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399 scan |= SCAN_INQUIRY;
400
401 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
402 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300403 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404
405failed:
406 hci_dev_unlock_bh(hdev);
407 hci_dev_put(hdev);
408
409 return err;
410}
411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
413 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200414{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200415 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200416 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300417 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418 u8 scan;
419 int err;
420
421 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100425 if (len != sizeof(*cp))
426 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
427
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431
432 hci_dev_lock_bh(hdev);
433
434 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200436 goto failed;
437 }
438
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100446 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200447 goto failed;
448 }
449
Szymon Janc4e51eae2011-02-25 19:05:48 +0100450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 if (!cmd) {
452 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300454 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200455
Johan Hedberg72a734e2010-12-30 00:38:22 +0200456 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 scan = SCAN_PAGE;
458 else
459 scan = 0;
460
461 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
462 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300463 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464
465failed:
466 hci_dev_unlock_bh(hdev);
467 hci_dev_put(hdev);
468
469 return err;
470}
471
Szymon Janc4e51eae2011-02-25 19:05:48 +0100472static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
473 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200474{
475 struct sk_buff *skb;
476 struct mgmt_hdr *hdr;
477
478 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
479 if (!skb)
480 return -ENOMEM;
481
482 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
483
484 hdr = (void *) skb_put(skb, sizeof(*hdr));
485 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100486 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200487 hdr->len = cpu_to_le16(data_len);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
Johan Hedberg053f0212011-01-26 13:07:10 +0200498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200501
Johan Hedberga38528f2011-01-22 06:46:43 +0200502 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200505}
506
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512 int err;
513
514 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
Szymon Janc4e51eae2011-02-25 19:05:48 +0100521 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200522 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
525 hci_dev_lock_bh(hdev);
526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 if (err < 0)
534 goto failed;
535
Johan Hedbergc542a062011-01-26 13:11:03 +0200536 ev.val = cp->val;
537
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539
540failed:
541 hci_dev_unlock_bh(hdev);
542 hci_dev_put(hdev);
543
544 return err;
545}
546
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200547static u8 get_service_classes(struct hci_dev *hdev)
548{
549 struct list_head *p;
550 u8 val = 0;
551
552 list_for_each(p, &hdev->uuids) {
553 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
554
555 val |= uuid->svc_hint;
556 }
557
558 return val;
559}
560
561static int update_class(struct hci_dev *hdev)
562{
563 u8 cod[3];
564
565 BT_DBG("%s", hdev->name);
566
567 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
568 return 0;
569
570 cod[0] = hdev->minor_class;
571 cod[1] = hdev->major_class;
572 cod[2] = get_service_classes(hdev);
573
574 if (memcmp(cod, hdev->dev_class, 3) == 0)
575 return 0;
576
577 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
578}
579
Szymon Janc4e51eae2011-02-25 19:05:48 +0100580static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200581{
582 struct mgmt_cp_add_uuid *cp;
583 struct hci_dev *hdev;
584 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200585 int err;
586
587 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200588
Szymon Janc4e51eae2011-02-25 19:05:48 +0100589 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200590
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100591 if (len != sizeof(*cp))
592 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
593
Szymon Janc4e51eae2011-02-25 19:05:48 +0100594 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200595 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100596 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200597
598 hci_dev_lock_bh(hdev);
599
600 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
601 if (!uuid) {
602 err = -ENOMEM;
603 goto failed;
604 }
605
606 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200607 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200608
609 list_add(&uuid->list, &hdev->uuids);
610
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200611 err = update_class(hdev);
612 if (err < 0)
613 goto failed;
614
Szymon Janc4e51eae2011-02-25 19:05:48 +0100615 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200616
617failed:
618 hci_dev_unlock_bh(hdev);
619 hci_dev_put(hdev);
620
621 return err;
622}
623
Szymon Janc4e51eae2011-02-25 19:05:48 +0100624static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200625{
626 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100627 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200628 struct hci_dev *hdev;
629 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 +0200630 int err, found;
631
632 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200633
Szymon Janc4e51eae2011-02-25 19:05:48 +0100634 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200635
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100636 if (len != sizeof(*cp))
637 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
638
Szymon Janc4e51eae2011-02-25 19:05:48 +0100639 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200640 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100641 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200642
643 hci_dev_lock_bh(hdev);
644
645 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
646 err = hci_uuids_clear(hdev);
647 goto unlock;
648 }
649
650 found = 0;
651
652 list_for_each_safe(p, n, &hdev->uuids) {
653 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
654
655 if (memcmp(match->uuid, cp->uuid, 16) != 0)
656 continue;
657
658 list_del(&match->list);
659 found++;
660 }
661
662 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100663 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200664 goto unlock;
665 }
666
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200667 err = update_class(hdev);
668 if (err < 0)
669 goto unlock;
670
Szymon Janc4e51eae2011-02-25 19:05:48 +0100671 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200672
673unlock:
674 hci_dev_unlock_bh(hdev);
675 hci_dev_put(hdev);
676
677 return err;
678}
679
Szymon Janc4e51eae2011-02-25 19:05:48 +0100680static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
681 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200682{
683 struct hci_dev *hdev;
684 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200685 int err;
686
687 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200688
Szymon Janc4e51eae2011-02-25 19:05:48 +0100689 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100691 if (len != sizeof(*cp))
692 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
693
Szymon Janc4e51eae2011-02-25 19:05:48 +0100694 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200695 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100696 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200697
698 hci_dev_lock_bh(hdev);
699
700 hdev->major_class = cp->major;
701 hdev->minor_class = cp->minor;
702
703 err = update_class(hdev);
704
705 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100706 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200707
708 hci_dev_unlock_bh(hdev);
709 hci_dev_put(hdev);
710
711 return err;
712}
713
Szymon Janc4e51eae2011-02-25 19:05:48 +0100714static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
715 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200716{
717 struct hci_dev *hdev;
718 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200719 int err;
720
721 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200722
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100723 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100724 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100725
Szymon Janc4e51eae2011-02-25 19:05:48 +0100726 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200727 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100728 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200729
730 hci_dev_lock_bh(hdev);
731
Szymon Janc4e51eae2011-02-25 19:05:48 +0100732 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200733
734 if (cp->enable) {
735 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
736 err = 0;
737 } else {
738 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
739 err = update_class(hdev);
740 }
741
742 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100743 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
744 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200745
746 hci_dev_unlock_bh(hdev);
747 hci_dev_put(hdev);
748
749 return err;
750}
751
Szymon Janc4e51eae2011-02-25 19:05:48 +0100752static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200753{
754 struct hci_dev *hdev;
755 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100756 u16 key_count, expected_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200757 int i;
758
759 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100760
761 if (len < sizeof(*cp))
762 return -EINVAL;
763
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200764 key_count = get_unaligned_le16(&cp->key_count);
765
766 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
767 if (expected_len != len) {
768 BT_ERR("load_keys: expected %u bytes, got %u bytes",
769 len, expected_len);
770 return -EINVAL;
771 }
772
Szymon Janc4e51eae2011-02-25 19:05:48 +0100773 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200774 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100775 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200776
Szymon Janc4e51eae2011-02-25 19:05:48 +0100777 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200778 key_count);
779
780 hci_dev_lock_bh(hdev);
781
782 hci_link_keys_clear(hdev);
783
784 set_bit(HCI_LINK_KEYS, &hdev->flags);
785
786 if (cp->debug_keys)
787 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
788 else
789 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
790
791 for (i = 0; i < key_count; i++) {
792 struct mgmt_key_info *key = &cp->keys[i];
793
794 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
795 key->pin_len);
796 }
797
798 hci_dev_unlock_bh(hdev);
799 hci_dev_put(hdev);
800
801 return 0;
802}
803
Szymon Janc4e51eae2011-02-25 19:05:48 +0100804static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200805{
806 struct hci_dev *hdev;
807 struct mgmt_cp_remove_key *cp;
808 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200809 int err;
810
811 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200812
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100813 if (len != sizeof(*cp))
814 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
815
Szymon Janc4e51eae2011-02-25 19:05:48 +0100816 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200817 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100818 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200819
820 hci_dev_lock_bh(hdev);
821
822 err = hci_remove_link_key(hdev, &cp->bdaddr);
823 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100824 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200825 goto unlock;
826 }
827
828 err = 0;
829
830 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
831 goto unlock;
832
833 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
834 if (conn) {
835 struct hci_cp_disconnect dc;
836
837 put_unaligned_le16(conn->handle, &dc.handle);
838 dc.reason = 0x13; /* Remote User Terminated Connection */
839 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
840 }
841
842unlock:
843 hci_dev_unlock_bh(hdev);
844 hci_dev_put(hdev);
845
846 return err;
847}
848
Szymon Janc4e51eae2011-02-25 19:05:48 +0100849static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200850{
851 struct hci_dev *hdev;
852 struct mgmt_cp_disconnect *cp;
853 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300854 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200855 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200856 int err;
857
858 BT_DBG("");
859
860 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200861
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100862 if (len != sizeof(*cp))
863 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
864
Szymon Janc4e51eae2011-02-25 19:05:48 +0100865 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200866 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100867 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200868
869 hci_dev_lock_bh(hdev);
870
871 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200873 goto failed;
874 }
875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
877 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200878 goto failed;
879 }
880
881 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
882 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200884 goto failed;
885 }
886
Szymon Janc4e51eae2011-02-25 19:05:48 +0100887 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300888 if (!cmd) {
889 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200890 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300891 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200892
893 put_unaligned_le16(conn->handle, &dc.handle);
894 dc.reason = 0x13; /* Remote User Terminated Connection */
895
896 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
897 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300898 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200899
900failed:
901 hci_dev_unlock_bh(hdev);
902 hci_dev_put(hdev);
903
904 return err;
905}
906
Szymon Janc8ce62842011-03-01 16:55:32 +0100907static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200908{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200909 struct mgmt_rp_get_connections *rp;
910 struct hci_dev *hdev;
911 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200912 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100913 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200914 int i, err;
915
916 BT_DBG("");
917
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200919 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200921
922 hci_dev_lock_bh(hdev);
923
924 count = 0;
925 list_for_each(p, &hdev->conn_hash.list) {
926 count++;
927 }
928
Johan Hedberga38528f2011-01-22 06:46:43 +0200929 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
930 rp = kmalloc(rp_len, GFP_ATOMIC);
931 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200932 err = -ENOMEM;
933 goto unlock;
934 }
935
Johan Hedberg2784eb42011-01-21 13:56:35 +0200936 put_unaligned_le16(count, &rp->conn_count);
937
938 read_lock(&hci_dev_list_lock);
939
940 i = 0;
941 list_for_each(p, &hdev->conn_hash.list) {
942 struct hci_conn *c = list_entry(p, struct hci_conn, list);
943
944 bacpy(&rp->conn[i++], &c->dst);
945 }
946
947 read_unlock(&hci_dev_list_lock);
948
Szymon Janc4e51eae2011-02-25 19:05:48 +0100949 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200950
951unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200952 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200953 hci_dev_unlock_bh(hdev);
954 hci_dev_put(hdev);
955 return err;
956}
957
Szymon Janc4e51eae2011-02-25 19:05:48 +0100958static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
959 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200960{
961 struct hci_dev *hdev;
962 struct mgmt_cp_pin_code_reply *cp;
963 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300964 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200965 int err;
966
967 BT_DBG("");
968
969 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200970
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100971 if (len != sizeof(*cp))
972 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
973
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200975 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200977
978 hci_dev_lock_bh(hdev);
979
980 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100981 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200982 goto failed;
983 }
984
Szymon Janc4e51eae2011-02-25 19:05:48 +0100985 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300986 if (!cmd) {
987 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200988 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300989 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200990
991 bacpy(&reply.bdaddr, &cp->bdaddr);
992 reply.pin_len = cp->pin_len;
993 memcpy(reply.pin_code, cp->pin_code, 16);
994
995 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
996 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300997 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200998
999failed:
1000 hci_dev_unlock_bh(hdev);
1001 hci_dev_put(hdev);
1002
1003 return err;
1004}
1005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1007 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001011 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001012 int err;
1013
1014 BT_DBG("");
1015
1016 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001017
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018 if (len != sizeof(*cp))
1019 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1020 EINVAL);
1021
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001023 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1025 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001026
1027 hci_dev_lock_bh(hdev);
1028
1029 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1031 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001032 goto failed;
1033 }
1034
Szymon Janc4e51eae2011-02-25 19:05:48 +01001035 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001036 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001037 if (!cmd) {
1038 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001039 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001040 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001041
Szymon Janc3cf2a4f2011-03-01 16:55:33 +01001042 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
Johan Hedberg980e1a52011-01-22 06:10:07 +02001043 &cp->bdaddr);
1044 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001045 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001046
1047failed:
1048 hci_dev_unlock_bh(hdev);
1049 hci_dev_put(hdev);
1050
1051 return err;
1052}
1053
Szymon Janc4e51eae2011-02-25 19:05:48 +01001054static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1055 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001056{
1057 struct hci_dev *hdev;
1058 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001059
1060 BT_DBG("");
1061
1062 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001063
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001064 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001065 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001066
Szymon Janc4e51eae2011-02-25 19:05:48 +01001067 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001068 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001069 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001070
1071 hci_dev_lock_bh(hdev);
1072
1073 hdev->io_capability = cp->io_capability;
1074
1075 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001076 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001077
1078 hci_dev_unlock_bh(hdev);
1079 hci_dev_put(hdev);
1080
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001082}
1083
Johan Hedberge9a416b2011-02-19 12:05:56 -03001084static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1085{
1086 struct hci_dev *hdev = conn->hdev;
1087 struct list_head *p;
1088
1089 list_for_each(p, &cmd_list) {
1090 struct pending_cmd *cmd;
1091
1092 cmd = list_entry(p, struct pending_cmd, list);
1093
1094 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1095 continue;
1096
1097 if (cmd->index != hdev->id)
1098 continue;
1099
1100 if (cmd->user_data != conn)
1101 continue;
1102
1103 return cmd;
1104 }
1105
1106 return NULL;
1107}
1108
1109static void pairing_complete(struct pending_cmd *cmd, u8 status)
1110{
1111 struct mgmt_rp_pair_device rp;
1112 struct hci_conn *conn = cmd->user_data;
1113
Johan Hedberge9a416b2011-02-19 12:05:56 -03001114 bacpy(&rp.bdaddr, &conn->dst);
1115 rp.status = status;
1116
Szymon Janc4e51eae2011-02-25 19:05:48 +01001117 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001118
1119 /* So we don't get further callbacks for this connection */
1120 conn->connect_cfm_cb = NULL;
1121 conn->security_cfm_cb = NULL;
1122 conn->disconn_cfm_cb = NULL;
1123
1124 hci_conn_put(conn);
1125
Johan Hedberga664b5b2011-02-19 12:06:02 -03001126 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001127}
1128
1129static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1130{
1131 struct pending_cmd *cmd;
1132
1133 BT_DBG("status %u", status);
1134
1135 cmd = find_pairing(conn);
1136 if (!cmd) {
1137 BT_DBG("Unable to find a pending command");
1138 return;
1139 }
1140
1141 pairing_complete(cmd, status);
1142}
1143
Szymon Janc4e51eae2011-02-25 19:05:48 +01001144static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001145{
1146 struct hci_dev *hdev;
1147 struct mgmt_cp_pair_device *cp;
1148 struct pending_cmd *cmd;
1149 u8 sec_level, auth_type;
1150 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001151 int err;
1152
1153 BT_DBG("");
1154
1155 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001156
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001157 if (len != sizeof(*cp))
1158 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1159
Szymon Janc4e51eae2011-02-25 19:05:48 +01001160 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001161 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001162 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001163
1164 hci_dev_lock_bh(hdev);
1165
1166 if (cp->io_cap == 0x03) {
1167 sec_level = BT_SECURITY_MEDIUM;
1168 auth_type = HCI_AT_DEDICATED_BONDING;
1169 } else {
1170 sec_level = BT_SECURITY_HIGH;
1171 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1172 }
1173
1174 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001175 if (IS_ERR(conn)) {
1176 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001177 goto unlock;
1178 }
1179
1180 if (conn->connect_cfm_cb) {
1181 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001182 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001183 goto unlock;
1184 }
1185
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001187 if (!cmd) {
1188 err = -ENOMEM;
1189 hci_conn_put(conn);
1190 goto unlock;
1191 }
1192
1193 conn->connect_cfm_cb = pairing_complete_cb;
1194 conn->security_cfm_cb = pairing_complete_cb;
1195 conn->disconn_cfm_cb = pairing_complete_cb;
1196 conn->io_capability = cp->io_cap;
1197 cmd->user_data = conn;
1198
1199 if (conn->state == BT_CONNECTED &&
1200 hci_conn_security(conn, sec_level, auth_type))
1201 pairing_complete(cmd, 0);
1202
1203 err = 0;
1204
1205unlock:
1206 hci_dev_unlock_bh(hdev);
1207 hci_dev_put(hdev);
1208
1209 return err;
1210}
1211
Szymon Janc4e51eae2011-02-25 19:05:48 +01001212static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1213 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001214{
1215 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001216 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001217 struct pending_cmd *cmd;
1218 struct hci_dev *hdev;
1219 int err;
1220
1221 BT_DBG("");
1222
Johan Hedberga5c29682011-02-19 12:05:57 -03001223 if (success) {
1224 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1225 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1226 } else {
1227 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1228 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1229 }
1230
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001231 if (len != sizeof(*cp))
1232 return cmd_status(sk, index, mgmt_op, EINVAL);
1233
Szymon Janc4e51eae2011-02-25 19:05:48 +01001234 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001235 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001236 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001237
1238 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001240 goto failed;
1241 }
1242
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001244 if (!cmd) {
1245 err = -ENOMEM;
1246 goto failed;
1247 }
1248
1249 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001250 if (err < 0)
1251 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001252
1253failed:
1254 hci_dev_unlock_bh(hdev);
1255 hci_dev_put(hdev);
1256
1257 return err;
1258}
1259
Johan Hedbergb312b1612011-03-16 14:29:37 +02001260static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1261 u16 len)
1262{
1263 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1264 struct hci_cp_write_local_name hci_cp;
1265 struct hci_dev *hdev;
1266 struct pending_cmd *cmd;
1267 int err;
1268
1269 BT_DBG("");
1270
1271 if (len != sizeof(*mgmt_cp))
1272 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1273
1274 hdev = hci_dev_get(index);
1275 if (!hdev)
1276 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1277
1278 hci_dev_lock_bh(hdev);
1279
1280 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1281 if (!cmd) {
1282 err = -ENOMEM;
1283 goto failed;
1284 }
1285
1286 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1287 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1288 &hci_cp);
1289 if (err < 0)
1290 mgmt_pending_remove(cmd);
1291
1292failed:
1293 hci_dev_unlock_bh(hdev);
1294 hci_dev_put(hdev);
1295
1296 return err;
1297}
1298
Szymon Jancc35938b2011-03-22 13:12:21 +01001299static int read_local_oob_data(struct sock *sk, u16 index)
1300{
1301 struct hci_dev *hdev;
1302 struct pending_cmd *cmd;
1303 int err;
1304
1305 BT_DBG("hci%u", index);
1306
1307 hdev = hci_dev_get(index);
1308 if (!hdev)
1309 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1310 ENODEV);
1311
1312 hci_dev_lock_bh(hdev);
1313
1314 if (!test_bit(HCI_UP, &hdev->flags)) {
1315 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1316 ENETDOWN);
1317 goto unlock;
1318 }
1319
1320 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1321 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1322 EOPNOTSUPP);
1323 goto unlock;
1324 }
1325
1326 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1327 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1328 goto unlock;
1329 }
1330
1331 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1332 if (!cmd) {
1333 err = -ENOMEM;
1334 goto unlock;
1335 }
1336
1337 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1338 if (err < 0)
1339 mgmt_pending_remove(cmd);
1340
1341unlock:
1342 hci_dev_unlock_bh(hdev);
1343 hci_dev_put(hdev);
1344
1345 return err;
1346}
1347
Johan Hedberg03811012010-12-08 00:21:06 +02001348int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1349{
1350 unsigned char *buf;
1351 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001353 int err;
1354
1355 BT_DBG("got %zu bytes", msglen);
1356
1357 if (msglen < sizeof(*hdr))
1358 return -EINVAL;
1359
1360 buf = kmalloc(msglen, GFP_ATOMIC);
1361 if (!buf)
1362 return -ENOMEM;
1363
1364 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1365 err = -EFAULT;
1366 goto done;
1367 }
1368
1369 hdr = (struct mgmt_hdr *) buf;
1370 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001371 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001372 len = get_unaligned_le16(&hdr->len);
1373
1374 if (len != msglen - sizeof(*hdr)) {
1375 err = -EINVAL;
1376 goto done;
1377 }
1378
1379 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001380 case MGMT_OP_READ_VERSION:
1381 err = read_version(sk);
1382 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001383 case MGMT_OP_READ_INDEX_LIST:
1384 err = read_index_list(sk);
1385 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001386 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001388 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001390 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001391 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001392 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001394 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001395 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001396 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001397 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001398 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001399 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001400 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001401 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001402 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001403 break;
1404 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001406 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001407 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001408 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409 break;
1410 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001411 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001412 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001413 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001414 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001415 break;
1416 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001418 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001419 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001420 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001421 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001422 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001423 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001424 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001425 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001427 break;
1428 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001430 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001431 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001432 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001433 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001434 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001435 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001436 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001437 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001438 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001439 break;
1440 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001441 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001442 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001443 case MGMT_OP_SET_LOCAL_NAME:
1444 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1445 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001446 case MGMT_OP_READ_LOCAL_OOB_DATA:
1447 err = read_local_oob_data(sk, index);
1448 break;
1449
Johan Hedberg03811012010-12-08 00:21:06 +02001450 default:
1451 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001453 break;
1454 }
1455
Johan Hedberge41d8b42010-12-13 21:07:03 +02001456 if (err < 0)
1457 goto done;
1458
Johan Hedberg03811012010-12-08 00:21:06 +02001459 err = msglen;
1460
1461done:
1462 kfree(buf);
1463 return err;
1464}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001465
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001466int mgmt_index_added(u16 index)
1467{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001468 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001469}
1470
1471int mgmt_index_removed(u16 index)
1472{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001474}
1475
Johan Hedberg73f22f62010-12-29 16:00:25 +02001476struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001477 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001478 struct sock *sk;
1479};
1480
Johan Hedberg72a734e2010-12-30 00:38:22 +02001481static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001483 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001484 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485
Johan Hedberg72a734e2010-12-30 00:38:22 +02001486 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001487 return;
1488
Johan Hedberg053f0212011-01-26 13:07:10 +02001489 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001490
1491 list_del(&cmd->list);
1492
1493 if (match->sk == NULL) {
1494 match->sk = cmd->sk;
1495 sock_hold(match->sk);
1496 }
1497
1498 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001499}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001500
1501int mgmt_powered(u16 index, u8 powered)
1502{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001503 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001504 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001506
Johan Hedberg72a734e2010-12-30 00:38:22 +02001507 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001508
Johan Hedberg72a734e2010-12-30 00:38:22 +02001509 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001512
1513 if (match.sk)
1514 sock_put(match.sk);
1515
1516 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001517}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001518
Johan Hedberg73f22f62010-12-29 16:00:25 +02001519int mgmt_discoverable(u16 index, u8 discoverable)
1520{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001521 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001522 struct cmd_lookup match = { discoverable, NULL };
1523 int ret;
1524
Szymon Jancb8534e02011-03-01 16:55:34 +01001525 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02001526
Johan Hedberg72a734e2010-12-30 00:38:22 +02001527 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001528
Szymon Janc4e51eae2011-02-25 19:05:48 +01001529 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1530 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001531
1532 if (match.sk)
1533 sock_put(match.sk);
1534
1535 return ret;
1536}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001537
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001538int mgmt_connectable(u16 index, u8 connectable)
1539{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001540 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001541 struct cmd_lookup match = { connectable, NULL };
1542 int ret;
1543
Johan Hedberg72a734e2010-12-30 00:38:22 +02001544 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001545
Johan Hedberg72a734e2010-12-30 00:38:22 +02001546 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001547
Szymon Janc4e51eae2011-02-25 19:05:48 +01001548 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001549
1550 if (match.sk)
1551 sock_put(match.sk);
1552
1553 return ret;
1554}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001555
1556int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1557{
1558 struct mgmt_ev_new_key ev;
1559
1560 memset(&ev, 0, sizeof(ev));
1561
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001562 bacpy(&ev.key.bdaddr, &key->bdaddr);
1563 ev.key.type = key->type;
1564 memcpy(ev.key.val, key->val, 16);
1565 ev.key.pin_len = key->pin_len;
1566 ev.old_key_type = old_key_type;
1567
Szymon Janc4e51eae2011-02-25 19:05:48 +01001568 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001569}
Johan Hedbergf7520542011-01-20 12:34:39 +02001570
1571int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1572{
1573 struct mgmt_ev_connected ev;
1574
Johan Hedbergf7520542011-01-20 12:34:39 +02001575 bacpy(&ev.bdaddr, bdaddr);
1576
Szymon Janc4e51eae2011-02-25 19:05:48 +01001577 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001578}
1579
Johan Hedberg8962ee72011-01-20 12:40:27 +02001580static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1581{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001582 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001583 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001584 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001585
Johan Hedberga38528f2011-01-22 06:46:43 +02001586 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587
Szymon Janc4e51eae2011-02-25 19:05:48 +01001588 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001589
1590 *sk = cmd->sk;
1591 sock_hold(*sk);
1592
Johan Hedberga664b5b2011-02-19 12:06:02 -03001593 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001594}
1595
Johan Hedbergf7520542011-01-20 12:34:39 +02001596int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1597{
1598 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001599 struct sock *sk = NULL;
1600 int err;
1601
1602 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001603
Johan Hedbergf7520542011-01-20 12:34:39 +02001604 bacpy(&ev.bdaddr, bdaddr);
1605
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001607
1608 if (sk)
1609 sock_put(sk);
1610
1611 return err;
1612}
1613
1614int mgmt_disconnect_failed(u16 index)
1615{
1616 struct pending_cmd *cmd;
1617 int err;
1618
1619 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1620 if (!cmd)
1621 return -ENOENT;
1622
Szymon Janc4e51eae2011-02-25 19:05:48 +01001623 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001624
Johan Hedberga664b5b2011-02-19 12:06:02 -03001625 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001626
1627 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001628}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001629
1630int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1631{
1632 struct mgmt_ev_connect_failed ev;
1633
Johan Hedberg17d5c042011-01-22 06:09:08 +02001634 bacpy(&ev.bdaddr, bdaddr);
1635 ev.status = status;
1636
Szymon Janc4e51eae2011-02-25 19:05:48 +01001637 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001638}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001639
1640int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1641{
1642 struct mgmt_ev_pin_code_request ev;
1643
Johan Hedberg980e1a52011-01-22 06:10:07 +02001644 bacpy(&ev.bdaddr, bdaddr);
1645
Szymon Janc4e51eae2011-02-25 19:05:48 +01001646 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1647 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001648}
1649
1650int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1651{
1652 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001653 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001654 int err;
1655
1656 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1657 if (!cmd)
1658 return -ENOENT;
1659
Johan Hedbergac56fb12011-02-19 12:05:59 -03001660 bacpy(&rp.bdaddr, bdaddr);
1661 rp.status = status;
1662
Szymon Janc4e51eae2011-02-25 19:05:48 +01001663 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1664 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001665
Johan Hedberga664b5b2011-02-19 12:06:02 -03001666 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001667
1668 return err;
1669}
1670
1671int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1672{
1673 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001674 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001675 int err;
1676
1677 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1678 if (!cmd)
1679 return -ENOENT;
1680
Johan Hedbergac56fb12011-02-19 12:05:59 -03001681 bacpy(&rp.bdaddr, bdaddr);
1682 rp.status = status;
1683
Szymon Janc4e51eae2011-02-25 19:05:48 +01001684 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1685 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001686
Johan Hedberga664b5b2011-02-19 12:06:02 -03001687 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001688
1689 return err;
1690}
Johan Hedberga5c29682011-02-19 12:05:57 -03001691
1692int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1693{
1694 struct mgmt_ev_user_confirm_request ev;
1695
1696 BT_DBG("hci%u", index);
1697
Johan Hedberga5c29682011-02-19 12:05:57 -03001698 bacpy(&ev.bdaddr, bdaddr);
1699 put_unaligned_le32(value, &ev.value);
1700
Szymon Janc4e51eae2011-02-25 19:05:48 +01001701 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1702 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001703}
1704
1705static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1706 u8 opcode)
1707{
1708 struct pending_cmd *cmd;
1709 struct mgmt_rp_user_confirm_reply rp;
1710 int err;
1711
1712 cmd = mgmt_pending_find(opcode, index);
1713 if (!cmd)
1714 return -ENOENT;
1715
Johan Hedberga5c29682011-02-19 12:05:57 -03001716 bacpy(&rp.bdaddr, bdaddr);
1717 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001718 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001719
Johan Hedberga664b5b2011-02-19 12:06:02 -03001720 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001721
1722 return err;
1723}
1724
1725int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1726{
1727 return confirm_reply_complete(index, bdaddr, status,
1728 MGMT_OP_USER_CONFIRM_REPLY);
1729}
1730
Szymon Jancb8534e02011-03-01 16:55:34 +01001731int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03001732{
1733 return confirm_reply_complete(index, bdaddr, status,
1734 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1735}
Johan Hedberg2a611692011-02-19 12:06:00 -03001736
1737int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1738{
1739 struct mgmt_ev_auth_failed ev;
1740
Johan Hedberg2a611692011-02-19 12:06:00 -03001741 bacpy(&ev.bdaddr, bdaddr);
1742 ev.status = status;
1743
Szymon Janc4e51eae2011-02-25 19:05:48 +01001744 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001745}
Johan Hedbergb312b1612011-03-16 14:29:37 +02001746
1747int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
1748{
1749 struct pending_cmd *cmd;
1750 struct mgmt_cp_set_local_name ev;
1751 int err;
1752
1753 memset(&ev, 0, sizeof(ev));
1754 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
1755
1756 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
1757 if (!cmd)
1758 goto send_event;
1759
1760 if (status) {
1761 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
1762 goto failed;
1763 }
1764
1765 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
1766 sizeof(ev));
1767 if (err < 0)
1768 goto failed;
1769
1770send_event:
1771 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
1772 cmd ? cmd->sk : NULL);
1773
1774failed:
1775 if (cmd)
1776 mgmt_pending_remove(cmd);
1777 return err;
1778}
Szymon Jancc35938b2011-03-22 13:12:21 +01001779
1780int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
1781 u8 status)
1782{
1783 struct pending_cmd *cmd;
1784 int err;
1785
1786 BT_DBG("hci%u status %u", index, status);
1787
1788 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
1789 if (!cmd)
1790 return -ENOENT;
1791
1792 if (status) {
1793 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1794 EIO);
1795 } else {
1796 struct mgmt_rp_read_local_oob_data rp;
1797
1798 memcpy(rp.hash, hash, sizeof(rp.hash));
1799 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
1800
1801 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1802 &rp, sizeof(rp));
1803 }
1804
1805 mgmt_pending_remove(cmd);
1806
1807 return err;
1808}