blob: 98c92aee623961ab9fbc266b26dd966b8ae58dfd [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
44LIST_HEAD(cmd_list);
45
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
51
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 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);
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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200177
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200178 hci_del_off_timer(hdev);
179
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200195 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200196 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Janc4e51eae2011-02-25 19:05:48 +0100305 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
309 hci_dev_lock_bh(hdev);
310
311 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200312 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100313 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200314 goto failed;
315 }
316
Szymon Janc4e51eae2011-02-25 19:05:48 +0100317 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
318 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319 goto failed;
320 }
321
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300323 if (!cmd) {
324 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200325 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300326 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200327
Johan Hedberg72a734e2010-12-30 00:38:22 +0200328 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 queue_work(hdev->workqueue, &hdev->power_on);
330 else
331 queue_work(hdev->workqueue, &hdev->power_off);
332
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334
335failed:
336 hci_dev_unlock_bh(hdev);
337 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300338 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339}
340
Szymon Janc4e51eae2011-02-25 19:05:48 +0100341static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
342 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200343{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200344 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200345 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300346 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200347 u8 scan;
348 int err;
349
350 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353
Szymon Janc4e51eae2011-02-25 19:05:48 +0100354 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100356 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357
358 hci_dev_lock_bh(hdev);
359
360 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362 goto failed;
363 }
364
Szymon Janc4e51eae2011-02-25 19:05:48 +0100365 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
366 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
367 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 goto failed;
369 }
370
Johan Hedberg72a734e2010-12-30 00:38:22 +0200371 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374 goto failed;
375 }
376
Szymon Janc4e51eae2011-02-25 19:05:48 +0100377 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300378 if (!cmd) {
379 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300381 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382
383 scan = SCAN_PAGE;
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 scan |= SCAN_INQUIRY;
387
388 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
389 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300390 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391
392failed:
393 hci_dev_unlock_bh(hdev);
394 hci_dev_put(hdev);
395
396 return err;
397}
398
Szymon Janc4e51eae2011-02-25 19:05:48 +0100399static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
400 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200401{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200402 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200403 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300404 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200405 u8 scan;
406 int err;
407
408 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200409
Szymon Janc4e51eae2011-02-25 19:05:48 +0100410 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411
Szymon Janc4e51eae2011-02-25 19:05:48 +0100412 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100414 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415
416 hci_dev_lock_bh(hdev);
417
418 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100419 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200420 goto failed;
421 }
422
Szymon Janc4e51eae2011-02-25 19:05:48 +0100423 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
424 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
425 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426 goto failed;
427 }
428
Johan Hedberg72a734e2010-12-30 00:38:22 +0200429 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431 goto failed;
432 }
433
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300435 if (!cmd) {
436 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300438 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439
Johan Hedberg72a734e2010-12-30 00:38:22 +0200440 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200441 scan = SCAN_PAGE;
442 else
443 scan = 0;
444
445 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
446 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300447 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448
449failed:
450 hci_dev_unlock_bh(hdev);
451 hci_dev_put(hdev);
452
453 return err;
454}
455
Szymon Janc4e51eae2011-02-25 19:05:48 +0100456static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
457 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200458{
459 struct sk_buff *skb;
460 struct mgmt_hdr *hdr;
461
462 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
463 if (!skb)
464 return -ENOMEM;
465
466 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
467
468 hdr = (void *) skb_put(skb, sizeof(*hdr));
469 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100470 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200471 hdr->len = cpu_to_le16(data_len);
472
Szymon Janc4e51eae2011-02-25 19:05:48 +0100473 if (data)
474 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200475
476 hci_send_to_sock(NULL, skb, skip_sk);
477 kfree_skb(skb);
478
479 return 0;
480}
481
Johan Hedberg053f0212011-01-26 13:07:10 +0200482static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
483{
Johan Hedberga38528f2011-01-22 06:46:43 +0200484 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200485
Johan Hedberga38528f2011-01-22 06:46:43 +0200486 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200487
Szymon Janc4e51eae2011-02-25 19:05:48 +0100488 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200489}
490
Szymon Janc4e51eae2011-02-25 19:05:48 +0100491static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
492 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200493{
494 struct mgmt_mode *cp, ev;
495 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200496 int err;
497
498 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200501
Szymon Janc4e51eae2011-02-25 19:05:48 +0100502 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200503 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200505
506 hci_dev_lock_bh(hdev);
507
508 if (cp->val)
509 set_bit(HCI_PAIRABLE, &hdev->flags);
510 else
511 clear_bit(HCI_PAIRABLE, &hdev->flags);
512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200514 if (err < 0)
515 goto failed;
516
Johan Hedbergc542a062011-01-26 13:11:03 +0200517 ev.val = cp->val;
518
Szymon Janc4e51eae2011-02-25 19:05:48 +0100519 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200520
521failed:
522 hci_dev_unlock_bh(hdev);
523 hci_dev_put(hdev);
524
525 return err;
526}
527
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200528static u8 get_service_classes(struct hci_dev *hdev)
529{
530 struct list_head *p;
531 u8 val = 0;
532
533 list_for_each(p, &hdev->uuids) {
534 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
535
536 val |= uuid->svc_hint;
537 }
538
539 return val;
540}
541
542static int update_class(struct hci_dev *hdev)
543{
544 u8 cod[3];
545
546 BT_DBG("%s", hdev->name);
547
548 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
549 return 0;
550
551 cod[0] = hdev->minor_class;
552 cod[1] = hdev->major_class;
553 cod[2] = get_service_classes(hdev);
554
555 if (memcmp(cod, hdev->dev_class, 3) == 0)
556 return 0;
557
558 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
559}
560
Szymon Janc4e51eae2011-02-25 19:05:48 +0100561static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200562{
563 struct mgmt_cp_add_uuid *cp;
564 struct hci_dev *hdev;
565 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200566 int err;
567
568 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200569
Szymon Janc4e51eae2011-02-25 19:05:48 +0100570 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200571
Szymon Janc4e51eae2011-02-25 19:05:48 +0100572 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200573 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100574 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200575
576 hci_dev_lock_bh(hdev);
577
578 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
579 if (!uuid) {
580 err = -ENOMEM;
581 goto failed;
582 }
583
584 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200585 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200586
587 list_add(&uuid->list, &hdev->uuids);
588
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200589 err = update_class(hdev);
590 if (err < 0)
591 goto failed;
592
Szymon Janc4e51eae2011-02-25 19:05:48 +0100593 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200594
595failed:
596 hci_dev_unlock_bh(hdev);
597 hci_dev_put(hdev);
598
599 return err;
600}
601
Szymon Janc4e51eae2011-02-25 19:05:48 +0100602static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200603{
604 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100605 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200606 struct hci_dev *hdev;
607 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 +0200608 int err, found;
609
610 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200611
Szymon Janc4e51eae2011-02-25 19:05:48 +0100612 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200613
Szymon Janc4e51eae2011-02-25 19:05:48 +0100614 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200615 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100616 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200617
618 hci_dev_lock_bh(hdev);
619
620 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
621 err = hci_uuids_clear(hdev);
622 goto unlock;
623 }
624
625 found = 0;
626
627 list_for_each_safe(p, n, &hdev->uuids) {
628 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
629
630 if (memcmp(match->uuid, cp->uuid, 16) != 0)
631 continue;
632
633 list_del(&match->list);
634 found++;
635 }
636
637 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100638 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200639 goto unlock;
640 }
641
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200642 err = update_class(hdev);
643 if (err < 0)
644 goto unlock;
645
Szymon Janc4e51eae2011-02-25 19:05:48 +0100646 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200647
648unlock:
649 hci_dev_unlock_bh(hdev);
650 hci_dev_put(hdev);
651
652 return err;
653}
654
Szymon Janc4e51eae2011-02-25 19:05:48 +0100655static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
656 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200657{
658 struct hci_dev *hdev;
659 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200660 int err;
661
662 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200663
Szymon Janc4e51eae2011-02-25 19:05:48 +0100664 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200665
Szymon Janc4e51eae2011-02-25 19:05:48 +0100666 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200667 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100668 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200669
670 hci_dev_lock_bh(hdev);
671
672 hdev->major_class = cp->major;
673 hdev->minor_class = cp->minor;
674
675 err = update_class(hdev);
676
677 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100678 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200679
680 hci_dev_unlock_bh(hdev);
681 hci_dev_put(hdev);
682
683 return err;
684}
685
Szymon Janc4e51eae2011-02-25 19:05:48 +0100686static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
687 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200688{
689 struct hci_dev *hdev;
690 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200691 int err;
692
693 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200694
Szymon Janc4e51eae2011-02-25 19:05:48 +0100695 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100697 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200698
699 hci_dev_lock_bh(hdev);
700
Szymon Janc4e51eae2011-02-25 19:05:48 +0100701 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702
703 if (cp->enable) {
704 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
705 err = 0;
706 } else {
707 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
708 err = update_class(hdev);
709 }
710
711 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100712 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
713 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200714
715 hci_dev_unlock_bh(hdev);
716 hci_dev_put(hdev);
717
718 return err;
719}
720
Szymon Janc4e51eae2011-02-25 19:05:48 +0100721static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200722{
723 struct hci_dev *hdev;
724 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100725 u16 key_count, expected_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200726 int i;
727
728 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200729 key_count = get_unaligned_le16(&cp->key_count);
730
731 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
732 if (expected_len != len) {
733 BT_ERR("load_keys: expected %u bytes, got %u bytes",
734 len, expected_len);
735 return -EINVAL;
736 }
737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200739 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200741
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200743 key_count);
744
745 hci_dev_lock_bh(hdev);
746
747 hci_link_keys_clear(hdev);
748
749 set_bit(HCI_LINK_KEYS, &hdev->flags);
750
751 if (cp->debug_keys)
752 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
753 else
754 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
755
756 for (i = 0; i < key_count; i++) {
757 struct mgmt_key_info *key = &cp->keys[i];
758
759 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
760 key->pin_len);
761 }
762
763 hci_dev_unlock_bh(hdev);
764 hci_dev_put(hdev);
765
766 return 0;
767}
768
Szymon Janc4e51eae2011-02-25 19:05:48 +0100769static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200770{
771 struct hci_dev *hdev;
772 struct mgmt_cp_remove_key *cp;
773 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200774 int err;
775
776 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200777
Szymon Janc4e51eae2011-02-25 19:05:48 +0100778 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200779 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100780 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200781
782 hci_dev_lock_bh(hdev);
783
784 err = hci_remove_link_key(hdev, &cp->bdaddr);
785 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100786 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200787 goto unlock;
788 }
789
790 err = 0;
791
792 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
793 goto unlock;
794
795 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
796 if (conn) {
797 struct hci_cp_disconnect dc;
798
799 put_unaligned_le16(conn->handle, &dc.handle);
800 dc.reason = 0x13; /* Remote User Terminated Connection */
801 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
802 }
803
804unlock:
805 hci_dev_unlock_bh(hdev);
806 hci_dev_put(hdev);
807
808 return err;
809}
810
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +0200812{
813 struct hci_dev *hdev;
814 struct mgmt_cp_disconnect *cp;
815 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -0300816 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200817 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200818 int err;
819
820 BT_DBG("");
821
822 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200823
Szymon Janc4e51eae2011-02-25 19:05:48 +0100824 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200825 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100826 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200827
828 hci_dev_lock_bh(hdev);
829
830 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100831 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200832 goto failed;
833 }
834
Szymon Janc4e51eae2011-02-25 19:05:48 +0100835 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
836 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200837 goto failed;
838 }
839
840 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
841 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100842 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200843 goto failed;
844 }
845
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300847 if (!cmd) {
848 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +0200849 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300850 }
Johan Hedberg8962ee72011-01-20 12:40:27 +0200851
852 put_unaligned_le16(conn->handle, &dc.handle);
853 dc.reason = 0x13; /* Remote User Terminated Connection */
854
855 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
856 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300857 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +0200858
859failed:
860 hci_dev_unlock_bh(hdev);
861 hci_dev_put(hdev);
862
863 return err;
864}
865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866static int get_connections(struct sock *sk, u16 index, unsigned char *data,
867 u16 len)
Johan Hedberg2784eb42011-01-21 13:56:35 +0200868{
Johan Hedberg2784eb42011-01-21 13:56:35 +0200869 struct mgmt_cp_get_connections *cp;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200870 struct mgmt_rp_get_connections *rp;
871 struct hci_dev *hdev;
872 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200873 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100874 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200875 int i, err;
876
877 BT_DBG("");
878
879 cp = (void *) data;
Johan Hedberg2784eb42011-01-21 13:56:35 +0200880
Szymon Janc4e51eae2011-02-25 19:05:48 +0100881 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200882 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200884
885 hci_dev_lock_bh(hdev);
886
887 count = 0;
888 list_for_each(p, &hdev->conn_hash.list) {
889 count++;
890 }
891
Johan Hedberga38528f2011-01-22 06:46:43 +0200892 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
893 rp = kmalloc(rp_len, GFP_ATOMIC);
894 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +0200895 err = -ENOMEM;
896 goto unlock;
897 }
898
Johan Hedberg2784eb42011-01-21 13:56:35 +0200899 put_unaligned_le16(count, &rp->conn_count);
900
901 read_lock(&hci_dev_list_lock);
902
903 i = 0;
904 list_for_each(p, &hdev->conn_hash.list) {
905 struct hci_conn *c = list_entry(p, struct hci_conn, list);
906
907 bacpy(&rp->conn[i++], &c->dst);
908 }
909
910 read_unlock(&hci_dev_list_lock);
911
Szymon Janc4e51eae2011-02-25 19:05:48 +0100912 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200913
914unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +0200915 kfree(rp);
Johan Hedberg2784eb42011-01-21 13:56:35 +0200916 hci_dev_unlock_bh(hdev);
917 hci_dev_put(hdev);
918 return err;
919}
920
Szymon Janc4e51eae2011-02-25 19:05:48 +0100921static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
922 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200923{
924 struct hci_dev *hdev;
925 struct mgmt_cp_pin_code_reply *cp;
926 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -0300927 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200928 int err;
929
930 BT_DBG("");
931
932 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200935 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200937
938 hci_dev_lock_bh(hdev);
939
940 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100941 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200942 goto failed;
943 }
944
Szymon Janc4e51eae2011-02-25 19:05:48 +0100945 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300946 if (!cmd) {
947 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200948 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300949 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200950
951 bacpy(&reply.bdaddr, &cp->bdaddr);
952 reply.pin_len = cp->pin_len;
953 memcpy(reply.pin_code, cp->pin_code, 16);
954
955 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
956 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300957 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200958
959failed:
960 hci_dev_unlock_bh(hdev);
961 hci_dev_put(hdev);
962
963 return err;
964}
965
Szymon Janc4e51eae2011-02-25 19:05:48 +0100966static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
967 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +0200968{
969 struct hci_dev *hdev;
970 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg366a0332011-02-19 12:05:55 -0300971 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200972 int err;
973
974 BT_DBG("");
975
976 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200977
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200979 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
981 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200982
983 hci_dev_lock_bh(hdev);
984
985 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100986 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
987 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +0200988 goto failed;
989 }
990
Szymon Janc4e51eae2011-02-25 19:05:48 +0100991 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
Johan Hedberg980e1a52011-01-22 06:10:07 +0200992 data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300993 if (!cmd) {
994 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +0200995 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300996 }
Johan Hedberg980e1a52011-01-22 06:10:07 +0200997
998 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
999 &cp->bdaddr);
1000 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001001 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001002
1003failed:
1004 hci_dev_unlock_bh(hdev);
1005 hci_dev_put(hdev);
1006
1007 return err;
1008}
1009
Szymon Janc4e51eae2011-02-25 19:05:48 +01001010static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1011 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001012{
1013 struct hci_dev *hdev;
1014 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001015
1016 BT_DBG("");
1017
1018 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001019
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001021 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001023
1024 hci_dev_lock_bh(hdev);
1025
1026 hdev->io_capability = cp->io_capability;
1027
1028 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
1029 hdev->io_capability);
1030
1031 hci_dev_unlock_bh(hdev);
1032 hci_dev_put(hdev);
1033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001035}
1036
Johan Hedberge9a416b2011-02-19 12:05:56 -03001037static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1038{
1039 struct hci_dev *hdev = conn->hdev;
1040 struct list_head *p;
1041
1042 list_for_each(p, &cmd_list) {
1043 struct pending_cmd *cmd;
1044
1045 cmd = list_entry(p, struct pending_cmd, list);
1046
1047 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1048 continue;
1049
1050 if (cmd->index != hdev->id)
1051 continue;
1052
1053 if (cmd->user_data != conn)
1054 continue;
1055
1056 return cmd;
1057 }
1058
1059 return NULL;
1060}
1061
1062static void pairing_complete(struct pending_cmd *cmd, u8 status)
1063{
1064 struct mgmt_rp_pair_device rp;
1065 struct hci_conn *conn = cmd->user_data;
1066
Johan Hedberge9a416b2011-02-19 12:05:56 -03001067 bacpy(&rp.bdaddr, &conn->dst);
1068 rp.status = status;
1069
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001071
1072 /* So we don't get further callbacks for this connection */
1073 conn->connect_cfm_cb = NULL;
1074 conn->security_cfm_cb = NULL;
1075 conn->disconn_cfm_cb = NULL;
1076
1077 hci_conn_put(conn);
1078
Johan Hedberga664b5b2011-02-19 12:06:02 -03001079 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001080}
1081
1082static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1083{
1084 struct pending_cmd *cmd;
1085
1086 BT_DBG("status %u", status);
1087
1088 cmd = find_pairing(conn);
1089 if (!cmd) {
1090 BT_DBG("Unable to find a pending command");
1091 return;
1092 }
1093
1094 pairing_complete(cmd, status);
1095}
1096
Szymon Janc4e51eae2011-02-25 19:05:48 +01001097static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001098{
1099 struct hci_dev *hdev;
1100 struct mgmt_cp_pair_device *cp;
1101 struct pending_cmd *cmd;
1102 u8 sec_level, auth_type;
1103 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001104 int err;
1105
1106 BT_DBG("");
1107
1108 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001109
Szymon Janc4e51eae2011-02-25 19:05:48 +01001110 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001111 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001112 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001113
1114 hci_dev_lock_bh(hdev);
1115
1116 if (cp->io_cap == 0x03) {
1117 sec_level = BT_SECURITY_MEDIUM;
1118 auth_type = HCI_AT_DEDICATED_BONDING;
1119 } else {
1120 sec_level = BT_SECURITY_HIGH;
1121 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1122 }
1123
1124 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
1125 if (!conn) {
1126 err = -ENOMEM;
1127 goto unlock;
1128 }
1129
1130 if (conn->connect_cfm_cb) {
1131 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001132 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001133 goto unlock;
1134 }
1135
Szymon Janc4e51eae2011-02-25 19:05:48 +01001136 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001137 if (!cmd) {
1138 err = -ENOMEM;
1139 hci_conn_put(conn);
1140 goto unlock;
1141 }
1142
1143 conn->connect_cfm_cb = pairing_complete_cb;
1144 conn->security_cfm_cb = pairing_complete_cb;
1145 conn->disconn_cfm_cb = pairing_complete_cb;
1146 conn->io_capability = cp->io_cap;
1147 cmd->user_data = conn;
1148
1149 if (conn->state == BT_CONNECTED &&
1150 hci_conn_security(conn, sec_level, auth_type))
1151 pairing_complete(cmd, 0);
1152
1153 err = 0;
1154
1155unlock:
1156 hci_dev_unlock_bh(hdev);
1157 hci_dev_put(hdev);
1158
1159 return err;
1160}
1161
Szymon Janc4e51eae2011-02-25 19:05:48 +01001162static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1163 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001164{
1165 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001166 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001167 struct pending_cmd *cmd;
1168 struct hci_dev *hdev;
1169 int err;
1170
1171 BT_DBG("");
1172
Johan Hedberga5c29682011-02-19 12:05:57 -03001173 if (success) {
1174 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1175 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1176 } else {
1177 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1178 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1179 }
1180
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001182 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001184
1185 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001187 goto failed;
1188 }
1189
Szymon Janc4e51eae2011-02-25 19:05:48 +01001190 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001191 if (!cmd) {
1192 err = -ENOMEM;
1193 goto failed;
1194 }
1195
1196 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001197 if (err < 0)
1198 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001199
1200failed:
1201 hci_dev_unlock_bh(hdev);
1202 hci_dev_put(hdev);
1203
1204 return err;
1205}
1206
Johan Hedberg03811012010-12-08 00:21:06 +02001207int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1208{
1209 unsigned char *buf;
1210 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001212 int err;
1213
1214 BT_DBG("got %zu bytes", msglen);
1215
1216 if (msglen < sizeof(*hdr))
1217 return -EINVAL;
1218
1219 buf = kmalloc(msglen, GFP_ATOMIC);
1220 if (!buf)
1221 return -ENOMEM;
1222
1223 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1224 err = -EFAULT;
1225 goto done;
1226 }
1227
1228 hdr = (struct mgmt_hdr *) buf;
1229 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001230 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001231 len = get_unaligned_le16(&hdr->len);
1232
1233 if (len != msglen - sizeof(*hdr)) {
1234 err = -EINVAL;
1235 goto done;
1236 }
1237
1238 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001239 case MGMT_OP_READ_VERSION:
1240 err = read_version(sk);
1241 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001242 case MGMT_OP_READ_INDEX_LIST:
1243 err = read_index_list(sk);
1244 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001245 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001247 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001248 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001250 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001251 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001253 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001254 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001256 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001257 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001258 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001259 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001260 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262 break;
1263 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001266 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001268 break;
1269 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001270 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001271 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001272 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001273 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001274 break;
1275 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001276 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001277 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001278 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001279 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001280 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001281 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001282 err = get_connections(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001283 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001284 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001285 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001286 break;
1287 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001289 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001290 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001291 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001292 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001293 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001295 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001296 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001297 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001298 break;
1299 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001301 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001302 default:
1303 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001304 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001305 break;
1306 }
1307
Johan Hedberge41d8b42010-12-13 21:07:03 +02001308 if (err < 0)
1309 goto done;
1310
Johan Hedberg03811012010-12-08 00:21:06 +02001311 err = msglen;
1312
1313done:
1314 kfree(buf);
1315 return err;
1316}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001317
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001318int mgmt_index_added(u16 index)
1319{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001320 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001321}
1322
1323int mgmt_index_removed(u16 index)
1324{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001326}
1327
Johan Hedberg73f22f62010-12-29 16:00:25 +02001328struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001329 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001330 struct sock *sk;
1331};
1332
Johan Hedberg72a734e2010-12-30 00:38:22 +02001333static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001334{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001335 struct mgmt_mode *cp = cmd->cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001336 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001337
Johan Hedberg72a734e2010-12-30 00:38:22 +02001338 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001339 return;
1340
Johan Hedberg053f0212011-01-26 13:07:10 +02001341 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001342
1343 list_del(&cmd->list);
1344
1345 if (match->sk == NULL) {
1346 match->sk = cmd->sk;
1347 sock_hold(match->sk);
1348 }
1349
1350 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001351}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001352
1353int mgmt_powered(u16 index, u8 powered)
1354{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001355 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001356 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001357 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001358
Johan Hedberg72a734e2010-12-30 00:38:22 +02001359 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001360
Johan Hedberg72a734e2010-12-30 00:38:22 +02001361 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001362
Szymon Janc4e51eae2011-02-25 19:05:48 +01001363 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001364
1365 if (match.sk)
1366 sock_put(match.sk);
1367
1368 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001369}
Johan Hedberg73f22f62010-12-29 16:00:25 +02001370
Johan Hedberg73f22f62010-12-29 16:00:25 +02001371int mgmt_discoverable(u16 index, u8 discoverable)
1372{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001373 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001374 struct cmd_lookup match = { discoverable, NULL };
1375 int ret;
1376
Johan Hedberg73f22f62010-12-29 16:00:25 +02001377 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
Johan Hedberg72a734e2010-12-30 00:38:22 +02001378 mode_rsp, &match);
1379
Johan Hedberg72a734e2010-12-30 00:38:22 +02001380 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001381
Szymon Janc4e51eae2011-02-25 19:05:48 +01001382 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
1383 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001384
1385 if (match.sk)
1386 sock_put(match.sk);
1387
1388 return ret;
1389}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001390
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001391int mgmt_connectable(u16 index, u8 connectable)
1392{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001393 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001394 struct cmd_lookup match = { connectable, NULL };
1395 int ret;
1396
Johan Hedberg72a734e2010-12-30 00:38:22 +02001397 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001398
Johan Hedberg72a734e2010-12-30 00:38:22 +02001399 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001400
Szymon Janc4e51eae2011-02-25 19:05:48 +01001401 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001402
1403 if (match.sk)
1404 sock_put(match.sk);
1405
1406 return ret;
1407}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001408
1409int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1410{
1411 struct mgmt_ev_new_key ev;
1412
1413 memset(&ev, 0, sizeof(ev));
1414
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001415 bacpy(&ev.key.bdaddr, &key->bdaddr);
1416 ev.key.type = key->type;
1417 memcpy(ev.key.val, key->val, 16);
1418 ev.key.pin_len = key->pin_len;
1419 ev.old_key_type = old_key_type;
1420
Szymon Janc4e51eae2011-02-25 19:05:48 +01001421 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001422}
Johan Hedbergf7520542011-01-20 12:34:39 +02001423
1424int mgmt_connected(u16 index, bdaddr_t *bdaddr)
1425{
1426 struct mgmt_ev_connected ev;
1427
Johan Hedbergf7520542011-01-20 12:34:39 +02001428 bacpy(&ev.bdaddr, bdaddr);
1429
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02001431}
1432
Johan Hedberg8962ee72011-01-20 12:40:27 +02001433static void disconnect_rsp(struct pending_cmd *cmd, void *data)
1434{
1435 struct mgmt_cp_disconnect *cp = cmd->cmd;
1436 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02001437 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001438
Johan Hedberga38528f2011-01-22 06:46:43 +02001439 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001440
Szymon Janc4e51eae2011-02-25 19:05:48 +01001441 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001442
1443 *sk = cmd->sk;
1444 sock_hold(*sk);
1445
Johan Hedberga664b5b2011-02-19 12:06:02 -03001446 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001447}
1448
Johan Hedbergf7520542011-01-20 12:34:39 +02001449int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
1450{
1451 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001452 struct sock *sk = NULL;
1453 int err;
1454
1455 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02001456
Johan Hedbergf7520542011-01-20 12:34:39 +02001457 bacpy(&ev.bdaddr, bdaddr);
1458
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001460
1461 if (sk)
1462 sock_put(sk);
1463
1464 return err;
1465}
1466
1467int mgmt_disconnect_failed(u16 index)
1468{
1469 struct pending_cmd *cmd;
1470 int err;
1471
1472 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
1473 if (!cmd)
1474 return -ENOENT;
1475
Szymon Janc4e51eae2011-02-25 19:05:48 +01001476 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001477
Johan Hedberga664b5b2011-02-19 12:06:02 -03001478 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001479
1480 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02001481}
Johan Hedberg17d5c042011-01-22 06:09:08 +02001482
1483int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1484{
1485 struct mgmt_ev_connect_failed ev;
1486
Johan Hedberg17d5c042011-01-22 06:09:08 +02001487 bacpy(&ev.bdaddr, bdaddr);
1488 ev.status = status;
1489
Szymon Janc4e51eae2011-02-25 19:05:48 +01001490 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02001491}
Johan Hedberg980e1a52011-01-22 06:10:07 +02001492
1493int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1494{
1495 struct mgmt_ev_pin_code_request ev;
1496
Johan Hedberg980e1a52011-01-22 06:10:07 +02001497 bacpy(&ev.bdaddr, bdaddr);
1498
Szymon Janc4e51eae2011-02-25 19:05:48 +01001499 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
1500 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001501}
1502
1503int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1504{
1505 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001506 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001507 int err;
1508
1509 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1510 if (!cmd)
1511 return -ENOENT;
1512
Johan Hedbergac56fb12011-02-19 12:05:59 -03001513 bacpy(&rp.bdaddr, bdaddr);
1514 rp.status = status;
1515
Szymon Janc4e51eae2011-02-25 19:05:48 +01001516 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
1517 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001518
Johan Hedberga664b5b2011-02-19 12:06:02 -03001519 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001520
1521 return err;
1522}
1523
1524int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1525{
1526 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03001527 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001528 int err;
1529
1530 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1531 if (!cmd)
1532 return -ENOENT;
1533
Johan Hedbergac56fb12011-02-19 12:05:59 -03001534 bacpy(&rp.bdaddr, bdaddr);
1535 rp.status = status;
1536
Szymon Janc4e51eae2011-02-25 19:05:48 +01001537 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
1538 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001539
Johan Hedberga664b5b2011-02-19 12:06:02 -03001540 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001541
1542 return err;
1543}
Johan Hedberga5c29682011-02-19 12:05:57 -03001544
1545int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
1546{
1547 struct mgmt_ev_user_confirm_request ev;
1548
1549 BT_DBG("hci%u", index);
1550
Johan Hedberga5c29682011-02-19 12:05:57 -03001551 bacpy(&ev.bdaddr, bdaddr);
1552 put_unaligned_le32(value, &ev.value);
1553
Szymon Janc4e51eae2011-02-25 19:05:48 +01001554 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
1555 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03001556}
1557
1558static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
1559 u8 opcode)
1560{
1561 struct pending_cmd *cmd;
1562 struct mgmt_rp_user_confirm_reply rp;
1563 int err;
1564
1565 cmd = mgmt_pending_find(opcode, index);
1566 if (!cmd)
1567 return -ENOENT;
1568
Johan Hedberga5c29682011-02-19 12:05:57 -03001569 bacpy(&rp.bdaddr, bdaddr);
1570 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001571 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03001572
Johan Hedberga664b5b2011-02-19 12:06:02 -03001573 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001574
1575 return err;
1576}
1577
1578int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1579{
1580 return confirm_reply_complete(index, bdaddr, status,
1581 MGMT_OP_USER_CONFIRM_REPLY);
1582}
1583
1584int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
1585 u8 status)
1586{
1587 return confirm_reply_complete(index, bdaddr, status,
1588 MGMT_OP_USER_CONFIRM_NEG_REPLY);
1589}
Johan Hedberg2a611692011-02-19 12:06:00 -03001590
1591int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1592{
1593 struct mgmt_ev_auth_failed ev;
1594
Johan Hedberg2a611692011-02-19 12:06:00 -03001595 bacpy(&ev.bdaddr, bdaddr);
1596 ev.status = status;
1597
Szymon Janc4e51eae2011-02-25 19:05:48 +01001598 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03001599}