blob: 46c3edc72cd1dcb85644bf7eaa663c1779a280f4 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
44LIST_HEAD(cmd_list);
45
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
52 BT_DBG("sock %p", sk);
53
54 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
55 if (!skb)
56 return -ENOMEM;
57
58 hdr = (void *) skb_put(skb, sizeof(*hdr));
59
60 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010061 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020062 hdr->len = cpu_to_le16(sizeof(*ev));
63
64 ev = (void *) skb_put(skb, sizeof(*ev));
65 ev->status = status;
66 put_unaligned_le16(cmd, &ev->opcode);
67
68 if (sock_queue_rcv_skb(sk, skb) < 0)
69 kfree_skb(skb);
70
71 return 0;
72}
73
Szymon Janc4e51eae2011-02-25 19:05:48 +010074static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
75 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020076{
77 struct sk_buff *skb;
78 struct mgmt_hdr *hdr;
79 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020080
81 BT_DBG("sock %p", sk);
82
Johan Hedberga38528f2011-01-22 06:46:43 +020083 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020084 if (!skb)
85 return -ENOMEM;
86
87 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020088
Johan Hedberg02d98122010-12-13 21:07:04 +020089 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010090 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020091 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020092
Johan Hedberga38528f2011-01-22 06:46:43 +020093 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
94 put_unaligned_le16(cmd, &ev->opcode);
95 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020096
97 if (sock_queue_rcv_skb(sk, skb) < 0)
98 kfree_skb(skb);
99
100 return 0;
101}
102
Johan Hedberga38528f2011-01-22 06:46:43 +0200103static int read_version(struct sock *sk)
104{
105 struct mgmt_rp_read_version rp;
106
107 BT_DBG("sock %p", sk);
108
109 rp.version = MGMT_VERSION;
110 put_unaligned_le16(MGMT_REVISION, &rp.revision);
111
Szymon Janc4e51eae2011-02-25 19:05:48 +0100112 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
113 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200114}
115
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200116static int read_index_list(struct sock *sk)
117{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200118 struct mgmt_rp_read_index_list *rp;
119 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200120 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200121 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200122 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200123
124 BT_DBG("sock %p", sk);
125
126 read_lock(&hci_dev_list_lock);
127
128 count = 0;
129 list_for_each(p, &hci_dev_list) {
130 count++;
131 }
132
Johan Hedberga38528f2011-01-22 06:46:43 +0200133 rp_len = sizeof(*rp) + (2 * count);
134 rp = kmalloc(rp_len, GFP_ATOMIC);
135 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100136 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200137 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100138 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200139
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 put_unaligned_le16(count, &rp->num_controllers);
141
142 i = 0;
143 list_for_each(p, &hci_dev_list) {
144 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200145
146 hci_del_off_timer(d);
147
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200148 set_bit(HCI_MGMT, &d->flags);
149
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200150 if (test_bit(HCI_SETUP, &d->flags))
151 continue;
152
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200153 put_unaligned_le16(d->id, &rp->index[i++]);
154 BT_DBG("Added hci%u", d->id);
155 }
156
157 read_unlock(&hci_dev_list_lock);
158
Szymon Janc4e51eae2011-02-25 19:05:48 +0100159 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
160 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200161
Johan Hedberga38528f2011-01-22 06:46:43 +0200162 kfree(rp);
163
164 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200165}
166
Szymon Janc4e51eae2011-02-25 19:05:48 +0100167static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200168{
Johan Hedberga38528f2011-01-22 06:46:43 +0200169 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200170 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200171
Szymon Janc4e51eae2011-02-25 19:05:48 +0100172 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200173
Szymon Janc4e51eae2011-02-25 19:05:48 +0100174 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200175 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100176 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200177
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200178 hci_del_off_timer(hdev);
179
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200180 hci_dev_lock_bh(hdev);
181
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200182 set_bit(HCI_MGMT, &hdev->flags);
183
Johan Hedberga38528f2011-01-22 06:46:43 +0200184 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200185
Johan Hedberga38528f2011-01-22 06:46:43 +0200186 rp.powered = test_bit(HCI_UP, &hdev->flags);
187 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
188 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
189 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200190
191 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200193 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200194 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197
Johan Hedberga38528f2011-01-22 06:46:43 +0200198 bacpy(&rp.bdaddr, &hdev->bdaddr);
199 memcpy(rp.features, hdev->features, 8);
200 memcpy(rp.dev_class, hdev->dev_class, 3);
201 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
202 rp.hci_ver = hdev->hci_ver;
203 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
205 hci_dev_unlock_bh(hdev);
206 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200207
Szymon Janc4e51eae2011-02-25 19:05:48 +0100208 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200209}
210
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200211static void mgmt_pending_free(struct pending_cmd *cmd)
212{
213 sock_put(cmd->sk);
214 kfree(cmd->cmd);
215 kfree(cmd);
216}
217
Johan Hedberg366a0332011-02-19 12:05:55 -0300218static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
219 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220{
221 struct pending_cmd *cmd;
222
223 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
224 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300225 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200226
227 cmd->opcode = opcode;
228 cmd->index = index;
229
230 cmd->cmd = kmalloc(len, GFP_ATOMIC);
231 if (!cmd->cmd) {
232 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300233 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200234 }
235
236 memcpy(cmd->cmd, data, len);
237
238 cmd->sk = sk;
239 sock_hold(sk);
240
241 list_add(&cmd->list, &cmd_list);
242
Johan Hedberg366a0332011-02-19 12:05:55 -0300243 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244}
245
246static void mgmt_pending_foreach(u16 opcode, int index,
247 void (*cb)(struct pending_cmd *cmd, void *data),
248 void *data)
249{
250 struct list_head *p, *n;
251
252 list_for_each_safe(p, n, &cmd_list) {
253 struct pending_cmd *cmd;
254
255 cmd = list_entry(p, struct pending_cmd, list);
256
257 if (cmd->opcode != opcode)
258 continue;
259
260 if (index >= 0 && cmd->index != index)
261 continue;
262
263 cb(cmd, data);
264 }
265}
266
267static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
268{
269 struct list_head *p;
270
271 list_for_each(p, &cmd_list) {
272 struct pending_cmd *cmd;
273
274 cmd = list_entry(p, struct pending_cmd, list);
275
276 if (cmd->opcode != opcode)
277 continue;
278
279 if (index >= 0 && cmd->index != index)
280 continue;
281
282 return cmd;
283 }
284
285 return NULL;
286}
287
Johan Hedberga664b5b2011-02-19 12:06:02 -0300288static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200289{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200290 list_del(&cmd->list);
291 mgmt_pending_free(cmd);
292}
293
Szymon Janc4e51eae2011-02-25 19:05:48 +0100294static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200295{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200296 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200297 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300298 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300299 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200300
301 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302
Szymon Janc4e51eae2011-02-25 19:05:48 +0100303 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100305 if (len != sizeof(*cp))
306 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
307
Szymon Janc4e51eae2011-02-25 19:05:48 +0100308 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200309 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100310 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
312 hci_dev_lock_bh(hdev);
313
314 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200315 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 goto failed;
318 }
319
Szymon Janc4e51eae2011-02-25 19:05:48 +0100320 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
321 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200322 goto failed;
323 }
324
Szymon Janc4e51eae2011-02-25 19:05:48 +0100325 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300326 if (!cmd) {
327 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300329 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330
Johan Hedberg72a734e2010-12-30 00:38:22 +0200331 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 queue_work(hdev->workqueue, &hdev->power_on);
333 else
334 queue_work(hdev->workqueue, &hdev->power_off);
335
Johan Hedberg366a0332011-02-19 12:05:55 -0300336 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
338failed:
339 hci_dev_unlock_bh(hdev);
340 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300341 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200342}
343
Szymon Janc4e51eae2011-02-25 19:05:48 +0100344static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
345 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200346{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200347 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200348 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300349 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200350 u8 scan;
351 int err;
352
353 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100357 if (len != sizeof(*cp))
358 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
359
Szymon Janc4e51eae2011-02-25 19:05:48 +0100360 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363
364 hci_dev_lock_bh(hdev);
365
366 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100367 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 goto failed;
369 }
370
Szymon Janc4e51eae2011-02-25 19:05:48 +0100371 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
372 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
373 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374 goto failed;
375 }
376
Johan Hedberg72a734e2010-12-30 00:38:22 +0200377 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200378 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 goto failed;
381 }
382
Szymon Janc4e51eae2011-02-25 19:05:48 +0100383 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300384 if (!cmd) {
385 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300387 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388
389 scan = SCAN_PAGE;
390
Johan Hedberg72a734e2010-12-30 00:38:22 +0200391 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200392 scan |= SCAN_INQUIRY;
393
394 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
395 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300396 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200397
398failed:
399 hci_dev_unlock_bh(hdev);
400 hci_dev_put(hdev);
401
402 return err;
403}
404
Szymon Janc4e51eae2011-02-25 19:05:48 +0100405static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
406 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200407{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200408 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200409 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300410 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411 u8 scan;
412 int err;
413
414 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415
Szymon Janc4e51eae2011-02-25 19:05:48 +0100416 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100418 if (len != sizeof(*cp))
419 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
420
Szymon Janc4e51eae2011-02-25 19:05:48 +0100421 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424
425 hci_dev_lock_bh(hdev);
426
427 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429 goto failed;
430 }
431
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
433 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
434 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 goto failed;
436 }
437
Johan Hedberg72a734e2010-12-30 00:38:22 +0200438 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200440 goto failed;
441 }
442
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300444 if (!cmd) {
445 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300447 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448
Johan Hedberg72a734e2010-12-30 00:38:22 +0200449 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 scan = SCAN_PAGE;
451 else
452 scan = 0;
453
454 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
455 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300456 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457
458failed:
459 hci_dev_unlock_bh(hdev);
460 hci_dev_put(hdev);
461
462 return err;
463}
464
Szymon Janc4e51eae2011-02-25 19:05:48 +0100465static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
466 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200467{
468 struct sk_buff *skb;
469 struct mgmt_hdr *hdr;
470
471 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
472 if (!skb)
473 return -ENOMEM;
474
475 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
476
477 hdr = (void *) skb_put(skb, sizeof(*hdr));
478 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100479 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200480 hdr->len = cpu_to_le16(data_len);
481
Szymon Janc4e51eae2011-02-25 19:05:48 +0100482 if (data)
483 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200484
485 hci_send_to_sock(NULL, skb, skip_sk);
486 kfree_skb(skb);
487
488 return 0;
489}
490
Johan Hedberg053f0212011-01-26 13:07:10 +0200491static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
492{
Johan Hedberga38528f2011-01-22 06:46:43 +0200493 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200494
Johan Hedberga38528f2011-01-22 06:46:43 +0200495 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200496
Szymon Janc4e51eae2011-02-25 19:05:48 +0100497 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200498}
499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
501 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200502{
503 struct mgmt_mode *cp, ev;
504 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200505 int err;
506
507 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200508
Szymon Janc4e51eae2011-02-25 19:05:48 +0100509 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200510
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100511 if (len != sizeof(*cp))
512 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
513
Szymon Janc4e51eae2011-02-25 19:05:48 +0100514 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200515 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
518 hci_dev_lock_bh(hdev);
519
520 if (cp->val)
521 set_bit(HCI_PAIRABLE, &hdev->flags);
522 else
523 clear_bit(HCI_PAIRABLE, &hdev->flags);
524
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526 if (err < 0)
527 goto failed;
528
Johan Hedbergc542a062011-01-26 13:11:03 +0200529 ev.val = cp->val;
530
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532
533failed:
534 hci_dev_unlock_bh(hdev);
535 hci_dev_put(hdev);
536
537 return err;
538}
539
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200540static u8 get_service_classes(struct hci_dev *hdev)
541{
542 struct list_head *p;
543 u8 val = 0;
544
545 list_for_each(p, &hdev->uuids) {
546 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
547
548 val |= uuid->svc_hint;
549 }
550
551 return val;
552}
553
554static int update_class(struct hci_dev *hdev)
555{
556 u8 cod[3];
557
558 BT_DBG("%s", hdev->name);
559
560 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
561 return 0;
562
563 cod[0] = hdev->minor_class;
564 cod[1] = hdev->major_class;
565 cod[2] = get_service_classes(hdev);
566
567 if (memcmp(cod, hdev->dev_class, 3) == 0)
568 return 0;
569
570 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
571}
572
Szymon Janc4e51eae2011-02-25 19:05:48 +0100573static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200574{
575 struct mgmt_cp_add_uuid *cp;
576 struct hci_dev *hdev;
577 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200578 int err;
579
580 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200581
Szymon Janc4e51eae2011-02-25 19:05:48 +0100582 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200583
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100584 if (len != sizeof(*cp))
585 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
586
Szymon Janc4e51eae2011-02-25 19:05:48 +0100587 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200588 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100589 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200590
591 hci_dev_lock_bh(hdev);
592
593 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
594 if (!uuid) {
595 err = -ENOMEM;
596 goto failed;
597 }
598
599 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200601
602 list_add(&uuid->list, &hdev->uuids);
603
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200604 err = update_class(hdev);
605 if (err < 0)
606 goto failed;
607
Szymon Janc4e51eae2011-02-25 19:05:48 +0100608 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200609
610failed:
611 hci_dev_unlock_bh(hdev);
612 hci_dev_put(hdev);
613
614 return err;
615}
616
Szymon Janc4e51eae2011-02-25 19:05:48 +0100617static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200618{
619 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100620 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200621 struct hci_dev *hdev;
622 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 +0200623 int err, found;
624
625 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200626
Szymon Janc4e51eae2011-02-25 19:05:48 +0100627 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200628
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100629 if (len != sizeof(*cp))
630 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
631
Szymon Janc4e51eae2011-02-25 19:05:48 +0100632 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200633 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100634 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200635
636 hci_dev_lock_bh(hdev);
637
638 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
639 err = hci_uuids_clear(hdev);
640 goto unlock;
641 }
642
643 found = 0;
644
645 list_for_each_safe(p, n, &hdev->uuids) {
646 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
647
648 if (memcmp(match->uuid, cp->uuid, 16) != 0)
649 continue;
650
651 list_del(&match->list);
652 found++;
653 }
654
655 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100656 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200657 goto unlock;
658 }
659
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200660 err = update_class(hdev);
661 if (err < 0)
662 goto unlock;
663
Szymon Janc4e51eae2011-02-25 19:05:48 +0100664 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200665
666unlock:
667 hci_dev_unlock_bh(hdev);
668 hci_dev_put(hdev);
669
670 return err;
671}
672
Szymon Janc4e51eae2011-02-25 19:05:48 +0100673static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
674 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200675{
676 struct hci_dev *hdev;
677 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200678 int err;
679
680 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200681
Szymon Janc4e51eae2011-02-25 19:05:48 +0100682 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200683
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100684 if (len != sizeof(*cp))
685 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
686
Szymon Janc4e51eae2011-02-25 19:05:48 +0100687 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200688 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100689 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690
691 hci_dev_lock_bh(hdev);
692
693 hdev->major_class = cp->major;
694 hdev->minor_class = cp->minor;
695
696 err = update_class(hdev);
697
698 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100699 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200700
701 hci_dev_unlock_bh(hdev);
702 hci_dev_put(hdev);
703
704 return err;
705}
706
Szymon Janc4e51eae2011-02-25 19:05:48 +0100707static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
708 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200709{
710 struct hci_dev *hdev;
711 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200712 int err;
713
714 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200715
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100716 if (len != sizeof(*cp))
717 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
718 EINVAL);
719
Szymon Janc4e51eae2011-02-25 19:05:48 +0100720 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200721 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100722 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200723
724 hci_dev_lock_bh(hdev);
725
Szymon Janc4e51eae2011-02-25 19:05:48 +0100726 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200727
728 if (cp->enable) {
729 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
730 err = 0;
731 } else {
732 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
733 err = update_class(hdev);
734 }
735
736 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100737 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
738 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200739
740 hci_dev_unlock_bh(hdev);
741 hci_dev_put(hdev);
742
743 return err;
744}
745
Szymon Janc4e51eae2011-02-25 19:05:48 +0100746static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200747{
748 struct hci_dev *hdev;
749 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100750 u16 key_count, expected_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200751 int i;
752
753 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100754
755 if (len < sizeof(*cp))
756 return -EINVAL;
757
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200758 key_count = get_unaligned_le16(&cp->key_count);
759
760 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
761 if (expected_len != len) {
762 BT_ERR("load_keys: expected %u bytes, got %u bytes",
763 len, expected_len);
764 return -EINVAL;
765 }
766
Szymon Janc4e51eae2011-02-25 19:05:48 +0100767 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200768 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100769 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200770
Szymon Janc4e51eae2011-02-25 19:05:48 +0100771 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200772 key_count);
773
774 hci_dev_lock_bh(hdev);
775
776 hci_link_keys_clear(hdev);
777
778 set_bit(HCI_LINK_KEYS, &hdev->flags);
779
780 if (cp->debug_keys)
781 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
782 else
783 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
784
785 for (i = 0; i < key_count; i++) {
786 struct mgmt_key_info *key = &cp->keys[i];
787
788 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
789 key->pin_len);
790 }
791
792 hci_dev_unlock_bh(hdev);
793 hci_dev_put(hdev);
794
795 return 0;
796}
797
Szymon Janc4e51eae2011-02-25 19:05:48 +0100798static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200799{
800 struct hci_dev *hdev;
801 struct mgmt_cp_remove_key *cp;
802 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200803 int err;
804
805 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200806
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100807 if (len != sizeof(*cp))
808 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
809
Szymon Janc4e51eae2011-02-25 19:05:48 +0100810 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200811 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200813
814 hci_dev_lock_bh(hdev);
815
816 err = hci_remove_link_key(hdev, &cp->bdaddr);
817 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100818 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200819 goto unlock;
820 }
821
822 err = 0;
823
824 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
825 goto unlock;
826
827 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
828 if (conn) {
829 struct hci_cp_disconnect dc;
830
831 put_unaligned_le16(conn->handle, &dc.handle);
832 dc.reason = 0x13; /* Remote User Terminated Connection */
833 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
834 }
835
836unlock:
837 hci_dev_unlock_bh(hdev);
838 hci_dev_put(hdev);
839
840 return err;
841}
842
Szymon Janc4e51eae2011-02-25 19:05:48 +0100843static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200844{
845 struct hci_dev *hdev;
846 struct mgmt_cp_disconnect *cp;
847 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300848 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200849 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200850 int err;
851
852 BT_DBG("");
853
854 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200855
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100856 if (len != sizeof(*cp))
857 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
858
Szymon Janc4e51eae2011-02-25 19:05:48 +0100859 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200860 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100861 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200862
863 hci_dev_lock_bh(hdev);
864
865 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200867 goto failed;
868 }
869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
871 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200872 goto failed;
873 }
874
875 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
876 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200878 goto failed;
879 }
880
Szymon Janc4e51eae2011-02-25 19:05:48 +0100881 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300882 if (!cmd) {
883 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200884 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300885 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200886
887 put_unaligned_le16(conn->handle, &dc.handle);
888 dc.reason = 0x13; /* Remote User Terminated Connection */
889
890 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
891 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300892 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200893
894failed:
895 hci_dev_unlock_bh(hdev);
896 hci_dev_put(hdev);
897
898 return err;
899}
900
Szymon Janc4e51eae2011-02-25 19:05:48 +0100901static int get_connections(struct sock *sk, u16 index, unsigned char *data,
902 u16 len)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200903{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200904 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200905 struct mgmt_rp_get_connections *rp;
906 struct hci_dev *hdev;
907 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200908 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200910 int i, err;
911
912 BT_DBG("");
913
914 cp = (void *) data;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200915
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200917 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200919
920 hci_dev_lock_bh(hdev);
921
922 count = 0;
923 list_for_each(p, &hdev->conn_hash.list) {
924 count++;
925 }
926
Johan Hedberga38528f2011-01-22 06:46:43 +0200927 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
928 rp = kmalloc(rp_len, GFP_ATOMIC);
929 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200930 err = -ENOMEM;
931 goto unlock;
932 }
933
Johan Hedberg2784eb42011-01-21 13:56:35 +0200934 put_unaligned_le16(count, &rp->conn_count);
935
936 read_lock(&hci_dev_list_lock);
937
938 i = 0;
939 list_for_each(p, &hdev->conn_hash.list) {
940 struct hci_conn *c = list_entry(p, struct hci_conn, list);
941
942 bacpy(&rp->conn[i++], &c->dst);
943 }
944
945 read_unlock(&hci_dev_list_lock);
946
Szymon Janc4e51eae2011-02-25 19:05:48 +0100947 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200948
949unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200950 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200951 hci_dev_unlock_bh(hdev);
952 hci_dev_put(hdev);
953 return err;
954}
955
Szymon Janc4e51eae2011-02-25 19:05:48 +0100956static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
957 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200958{
959 struct hci_dev *hdev;
960 struct mgmt_cp_pin_code_reply *cp;
961 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300962 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200963 int err;
964
965 BT_DBG("");
966
967 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200968
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100969 if (len != sizeof(*cp))
970 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
971
Szymon Janc4e51eae2011-02-25 19:05:48 +0100972 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200973 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200975
976 hci_dev_lock_bh(hdev);
977
978 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200980 goto failed;
981 }
982
Szymon Janc4e51eae2011-02-25 19:05:48 +0100983 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300984 if (!cmd) {
985 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200986 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300987 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200988
989 bacpy(&reply.bdaddr, &cp->bdaddr);
990 reply.pin_len = cp->pin_len;
991 memcpy(reply.pin_code, cp->pin_code, 16);
992
993 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
994 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300995 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200996
997failed:
998 hci_dev_unlock_bh(hdev);
999 hci_dev_put(hdev);
1000
1001 return err;
1002}
1003
Szymon Janc4e51eae2011-02-25 19:05:48 +01001004static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1005 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001006{
1007 struct hci_dev *hdev;
1008 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -03001009 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001010 int err;
1011
1012 BT_DBG("");
1013
1014 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001015
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001016 if (len != sizeof(*cp))
1017 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1018 EINVAL);
1019
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001021 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1023 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001024
1025 hci_dev_lock_bh(hdev);
1026
1027 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001028 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1029 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001030 goto failed;
1031 }
1032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +02001034 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001035 if (!cmd) {
1036 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001037 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001038 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001039
1040 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1041 &cp->bdaddr);
1042 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001043 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001044
1045failed:
1046 hci_dev_unlock_bh(hdev);
1047 hci_dev_put(hdev);
1048
1049 return err;
1050}
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1053 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001054{
1055 struct hci_dev *hdev;
1056 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001057
1058 BT_DBG("");
1059
1060 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001061
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001062 if (len != sizeof(*cp))
1063 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1064 EINVAL);
1065
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,
1075 hdev->io_capability);
1076
1077 hci_dev_unlock_bh(hdev);
1078 hci_dev_put(hdev);
1079
Szymon Janc4e51eae2011-02-25 19:05:48 +01001080 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001081}
1082
Johan Hedberge9a416b2011-02-19 12:05:56 -03001083static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1084{
1085 struct hci_dev *hdev = conn->hdev;
1086 struct list_head *p;
1087
1088 list_for_each(p, &cmd_list) {
1089 struct pending_cmd *cmd;
1090
1091 cmd = list_entry(p, struct pending_cmd, list);
1092
1093 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1094 continue;
1095
1096 if (cmd->index != hdev->id)
1097 continue;
1098
1099 if (cmd->user_data != conn)
1100 continue;
1101
1102 return cmd;
1103 }
1104
1105 return NULL;
1106}
1107
1108static void pairing_complete(struct pending_cmd *cmd, u8 status)
1109{
1110 struct mgmt_rp_pair_device rp;
1111 struct hci_conn *conn = cmd->user_data;
1112
Johan Hedberge9a416b2011-02-19 12:05:56 -03001113 bacpy(&rp.bdaddr, &conn->dst);
1114 rp.status = status;
1115
Szymon Janc4e51eae2011-02-25 19:05:48 +01001116 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001117
1118 /* So we don't get further callbacks for this connection */
1119 conn->connect_cfm_cb = NULL;
1120 conn->security_cfm_cb = NULL;
1121 conn->disconn_cfm_cb = NULL;
1122
1123 hci_conn_put(conn);
1124
Johan Hedberga664b5b2011-02-19 12:06:02 -03001125 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001126}
1127
1128static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1129{
1130 struct pending_cmd *cmd;
1131
1132 BT_DBG("status %u", status);
1133
1134 cmd = find_pairing(conn);
1135 if (!cmd) {
1136 BT_DBG("Unable to find a pending command");
1137 return;
1138 }
1139
1140 pairing_complete(cmd, status);
1141}
1142
Szymon Janc4e51eae2011-02-25 19:05:48 +01001143static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001144{
1145 struct hci_dev *hdev;
1146 struct mgmt_cp_pair_device *cp;
1147 struct pending_cmd *cmd;
1148 u8 sec_level, auth_type;
1149 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001150 int err;
1151
1152 BT_DBG("");
1153
1154 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001155
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001156 if (len != sizeof(*cp))
1157 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1158
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001160 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001161 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001162
1163 hci_dev_lock_bh(hdev);
1164
1165 if (cp->io_cap == 0x03) {
1166 sec_level = BT_SECURITY_MEDIUM;
1167 auth_type = HCI_AT_DEDICATED_BONDING;
1168 } else {
1169 sec_level = BT_SECURITY_HIGH;
1170 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1171 }
1172
1173 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
Ville Tervo30e76272011-02-22 16:10:53 -03001174 if (IS_ERR(conn)) {
1175 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001176 goto unlock;
1177 }
1178
1179 if (conn->connect_cfm_cb) {
1180 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001182 goto unlock;
1183 }
1184
Szymon Janc4e51eae2011-02-25 19:05:48 +01001185 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001186 if (!cmd) {
1187 err = -ENOMEM;
1188 hci_conn_put(conn);
1189 goto unlock;
1190 }
1191
1192 conn->connect_cfm_cb = pairing_complete_cb;
1193 conn->security_cfm_cb = pairing_complete_cb;
1194 conn->disconn_cfm_cb = pairing_complete_cb;
1195 conn->io_capability = cp->io_cap;
1196 cmd->user_data = conn;
1197
1198 if (conn->state == BT_CONNECTED &&
1199 hci_conn_security(conn, sec_level, auth_type))
1200 pairing_complete(cmd, 0);
1201
1202 err = 0;
1203
1204unlock:
1205 hci_dev_unlock_bh(hdev);
1206 hci_dev_put(hdev);
1207
1208 return err;
1209}
1210
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1212 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001213{
1214 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001216 struct pending_cmd *cmd;
1217 struct hci_dev *hdev;
1218 int err;
1219
1220 BT_DBG("");
1221
Johan Hedberga5c29682011-02-19 12:05:57 -03001222 if (success) {
1223 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1224 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1225 } else {
1226 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1227 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1228 }
1229
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001230 if (len != sizeof(*cp))
1231 return cmd_status(sk, index, mgmt_op, EINVAL);
1232
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001234 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001236
1237 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001239 goto failed;
1240 }
1241
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001243 if (!cmd) {
1244 err = -ENOMEM;
1245 goto failed;
1246 }
1247
1248 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001249 if (err < 0)
1250 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001251
1252failed:
1253 hci_dev_unlock_bh(hdev);
1254 hci_dev_put(hdev);
1255
1256 return err;
1257}
1258
Johan Hedberg03811012010-12-08 00:21:06 +02001259int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1260{
1261 unsigned char *buf;
1262 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001264 int err;
1265
1266 BT_DBG("got %zu bytes", msglen);
1267
1268 if (msglen < sizeof(*hdr))
1269 return -EINVAL;
1270
1271 buf = kmalloc(msglen, GFP_ATOMIC);
1272 if (!buf)
1273 return -ENOMEM;
1274
1275 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1276 err = -EFAULT;
1277 goto done;
1278 }
1279
1280 hdr = (struct mgmt_hdr *) buf;
1281 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001282 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001283 len = get_unaligned_le16(&hdr->len);
1284
1285 if (len != msglen - sizeof(*hdr)) {
1286 err = -EINVAL;
1287 goto done;
1288 }
1289
1290 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001291 case MGMT_OP_READ_VERSION:
1292 err = read_version(sk);
1293 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001294 case MGMT_OP_READ_INDEX_LIST:
1295 err = read_index_list(sk);
1296 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001297 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001299 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001300 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001302 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001303 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001304 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001305 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001306 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001308 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001309 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001311 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001313 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314 break;
1315 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001316 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001317 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001318 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001320 break;
1321 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001322 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001323 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001324 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001326 break;
1327 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001328 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001329 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001330 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001331 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001332 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001333 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334 err = get_connections(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001335 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338 break;
1339 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001342 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001344 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001348 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001350 break;
1351 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001353 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001354 default:
1355 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001356 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001357 break;
1358 }
1359
Johan Hedberge41d8b42010-12-13 21:07:03 +02001360 if (err < 0)
1361 goto done;
1362
Johan Hedberg03811012010-12-08 00:21:06 +02001363 err = msglen;
1364
1365done:
1366 kfree(buf);
1367 return err;
1368}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001369
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001370int mgmt_index_added(u16 index)
1371{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001372 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001373}
1374
1375int mgmt_index_removed(u16 index)
1376{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001377 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001378}
1379
Johan Hedberg73f22f62010-12-29 16:00:25 +02001380struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001381 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001382 struct sock *sk;
1383};
1384
Johan Hedberg72a734e2010-12-30 00:38:22 +02001385static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001386{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001387 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001388 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389
Johan Hedberg72a734e2010-12-30 00:38:22 +02001390 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001391 return;
1392
Johan Hedberg053f0212011-01-26 13:07:10 +02001393 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001394
1395 list_del(&cmd->list);
1396
1397 if (match->sk == NULL) {
1398 match->sk = cmd->sk;
1399 sock_hold(match->sk);
1400 }
1401
1402 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001403}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001404
1405int mgmt_powered(u16 index, u8 powered)
1406{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001407 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001408 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001409 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001410
Johan Hedberg72a734e2010-12-30 00:38:22 +02001411 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001412
Johan Hedberg72a734e2010-12-30 00:38:22 +02001413 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001416
1417 if (match.sk)
1418 sock_put(match.sk);
1419
1420 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001421}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001422
Johan Hedberg73f22f62010-12-29 16:00:25 +02001423int mgmt_discoverable(u16 index, u8 discoverable)
1424{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001425 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001426 struct cmd_lookup match = { discoverable, NULL };
1427 int ret;
1428
Johan Hedberg73f22f62010-12-29 16:00:25 +02001429 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001430 mode_rsp, &match);
1431
Johan Hedberg72a734e2010-12-30 00:38:22 +02001432 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001433
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1435 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001436
1437 if (match.sk)
1438 sock_put(match.sk);
1439
1440 return ret;
1441}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001442
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001443int mgmt_connectable(u16 index, u8 connectable)
1444{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001445 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001446 struct cmd_lookup match = { connectable, NULL };
1447 int ret;
1448
Johan Hedberg72a734e2010-12-30 00:38:22 +02001449 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001450
Johan Hedberg72a734e2010-12-30 00:38:22 +02001451 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001454
1455 if (match.sk)
1456 sock_put(match.sk);
1457
1458 return ret;
1459}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460
1461int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1462{
1463 struct mgmt_ev_new_key ev;
1464
1465 memset(&ev, 0, sizeof(ev));
1466
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001467 bacpy(&ev.key.bdaddr, &key->bdaddr);
1468 ev.key.type = key->type;
1469 memcpy(ev.key.val, key->val, 16);
1470 ev.key.pin_len = key->pin_len;
1471 ev.old_key_type = old_key_type;
1472
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474}
Johan Hedbergf7520542011-01-20 12:34:39 +02001475
1476int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1477{
1478 struct mgmt_ev_connected ev;
1479
Johan Hedbergf7520542011-01-20 12:34:39 +02001480 bacpy(&ev.bdaddr, bdaddr);
1481
Szymon Janc4e51eae2011-02-25 19:05:48 +01001482 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001483}
1484
Johan Hedberg8962ee72011-01-20 12:40:27 +02001485static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1486{
1487 struct mgmt_cp_disconnect *cp = cmd->cmd;
1488 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001489 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001490
Johan Hedberga38528f2011-01-22 06:46:43 +02001491 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001492
Szymon Janc4e51eae2011-02-25 19:05:48 +01001493 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494
1495 *sk = cmd->sk;
1496 sock_hold(*sk);
1497
Johan Hedberga664b5b2011-02-19 12:06:02 -03001498 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001499}
1500
Johan Hedbergf7520542011-01-20 12:34:39 +02001501int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1502{
1503 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001504 struct sock *sk = NULL;
1505 int err;
1506
1507 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001508
Johan Hedbergf7520542011-01-20 12:34:39 +02001509 bacpy(&ev.bdaddr, bdaddr);
1510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001512
1513 if (sk)
1514 sock_put(sk);
1515
1516 return err;
1517}
1518
1519int mgmt_disconnect_failed(u16 index)
1520{
1521 struct pending_cmd *cmd;
1522 int err;
1523
1524 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1525 if (!cmd)
1526 return -ENOENT;
1527
Szymon Janc4e51eae2011-02-25 19:05:48 +01001528 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001529
Johan Hedberga664b5b2011-02-19 12:06:02 -03001530 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001531
1532 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001533}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001534
1535int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1536{
1537 struct mgmt_ev_connect_failed ev;
1538
Johan Hedberg17d5c042011-01-22 06:09:08 +02001539 bacpy(&ev.bdaddr, bdaddr);
1540 ev.status = status;
1541
Szymon Janc4e51eae2011-02-25 19:05:48 +01001542 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001543}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001544
1545int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1546{
1547 struct mgmt_ev_pin_code_request ev;
1548
Johan Hedberg980e1a52011-01-22 06:10:07 +02001549 bacpy(&ev.bdaddr, bdaddr);
1550
Szymon Janc4e51eae2011-02-25 19:05:48 +01001551 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1552 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001553}
1554
1555int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1556{
1557 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001558 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001559 int err;
1560
1561 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1562 if (!cmd)
1563 return -ENOENT;
1564
Johan Hedbergac56fb12011-02-19 12:05:59 -03001565 bacpy(&rp.bdaddr, bdaddr);
1566 rp.status = status;
1567
Szymon Janc4e51eae2011-02-25 19:05:48 +01001568 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1569 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001570
Johan Hedberga664b5b2011-02-19 12:06:02 -03001571 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001572
1573 return err;
1574}
1575
1576int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1577{
1578 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001579 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001580 int err;
1581
1582 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1583 if (!cmd)
1584 return -ENOENT;
1585
Johan Hedbergac56fb12011-02-19 12:05:59 -03001586 bacpy(&rp.bdaddr, bdaddr);
1587 rp.status = status;
1588
Szymon Janc4e51eae2011-02-25 19:05:48 +01001589 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1590 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001591
Johan Hedberga664b5b2011-02-19 12:06:02 -03001592 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001593
1594 return err;
1595}
Johan Hedberga5c29682011-02-19 12:05:57 -03001596
1597int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1598{
1599 struct mgmt_ev_user_confirm_request ev;
1600
1601 BT_DBG("hci%u", index);
1602
Johan Hedberga5c29682011-02-19 12:05:57 -03001603 bacpy(&ev.bdaddr, bdaddr);
1604 put_unaligned_le32(value, &ev.value);
1605
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1607 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001608}
1609
1610static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1611 u8 opcode)
1612{
1613 struct pending_cmd *cmd;
1614 struct mgmt_rp_user_confirm_reply rp;
1615 int err;
1616
1617 cmd = mgmt_pending_find(opcode, index);
1618 if (!cmd)
1619 return -ENOENT;
1620
Johan Hedberga5c29682011-02-19 12:05:57 -03001621 bacpy(&rp.bdaddr, bdaddr);
1622 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001623 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001624
Johan Hedberga664b5b2011-02-19 12:06:02 -03001625 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001626
1627 return err;
1628}
1629
1630int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1631{
1632 return confirm_reply_complete(index, bdaddr, status,
1633 MGMT_OP_USER_CONFIRM_REPLY);
1634}
1635
1636int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1637 u8 status)
1638{
1639 return confirm_reply_complete(index, bdaddr, status,
1640 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1641}
Johan Hedberg2a611692011-02-19 12:06:00 -03001642
1643int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1644{
1645 struct mgmt_ev_auth_failed ev;
1646
Johan Hedberg2a611692011-02-19 12:06:00 -03001647 bacpy(&ev.bdaddr, bdaddr);
1648 ev.status = status;
1649
Szymon Janc4e51eae2011-02-25 19:05:48 +01001650 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001651}