blob: 940858a48cbdbdbf562ef12645ebdfc568f23d78 [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>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040026#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020036struct pending_cmd {
37 struct list_head list;
38 __u16 opcode;
39 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010040 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030042 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043};
44
Johannes Bergb5ad8b72011-06-01 08:54:45 +020045static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020046
Szymon Janc4e51eae2011-02-25 19:05:48 +010047static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020048{
49 struct sk_buff *skb;
50 struct mgmt_hdr *hdr;
51 struct mgmt_ev_cmd_status *ev;
52
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
69 if (sock_queue_rcv_skb(sk, skb) < 0)
70 kfree_skb(skb);
71
72 return 0;
73}
74
Szymon Janc4e51eae2011-02-25 19:05:48 +010075static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
76 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020077{
78 struct sk_buff *skb;
79 struct mgmt_hdr *hdr;
80 struct mgmt_ev_cmd_complete *ev;
Johan Hedberg02d98122010-12-13 21:07:04 +020081
82 BT_DBG("sock %p", sk);
83
Johan Hedberga38528f2011-01-22 06:46:43 +020084 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020085 if (!skb)
86 return -ENOMEM;
87
88 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020089
Johan Hedberg02d98122010-12-13 21:07:04 +020090 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010091 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020092 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020093
Johan Hedberga38528f2011-01-22 06:46:43 +020094 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
95 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010096
97 if (rp)
98 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020099
100 if (sock_queue_rcv_skb(sk, skb) < 0)
101 kfree_skb(skb);
102
103 return 0;
104}
105
Johan Hedberga38528f2011-01-22 06:46:43 +0200106static int read_version(struct sock *sk)
107{
108 struct mgmt_rp_read_version rp;
109
110 BT_DBG("sock %p", sk);
111
112 rp.version = MGMT_VERSION;
113 put_unaligned_le16(MGMT_REVISION, &rp.revision);
114
Szymon Janc4e51eae2011-02-25 19:05:48 +0100115 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
116 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200117}
118
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200119static int read_index_list(struct sock *sk)
120{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200121 struct mgmt_rp_read_index_list *rp;
122 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200123 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200125 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126
127 BT_DBG("sock %p", sk);
128
129 read_lock(&hci_dev_list_lock);
130
131 count = 0;
132 list_for_each(p, &hci_dev_list) {
133 count++;
134 }
135
Johan Hedberga38528f2011-01-22 06:46:43 +0200136 rp_len = sizeof(*rp) + (2 * count);
137 rp = kmalloc(rp_len, GFP_ATOMIC);
138 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100139 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200140 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100141 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200142
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200143 put_unaligned_le16(count, &rp->num_controllers);
144
145 i = 0;
146 list_for_each(p, &hci_dev_list) {
147 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200148
149 hci_del_off_timer(d);
150
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200151 set_bit(HCI_MGMT, &d->flags);
152
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200153 if (test_bit(HCI_SETUP, &d->flags))
154 continue;
155
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 put_unaligned_le16(d->id, &rp->index[i++]);
157 BT_DBG("Added hci%u", d->id);
158 }
159
160 read_unlock(&hci_dev_list_lock);
161
Szymon Janc4e51eae2011-02-25 19:05:48 +0100162 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
163 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200164
Johan Hedberga38528f2011-01-22 06:46:43 +0200165 kfree(rp);
166
167 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200168}
169
Szymon Janc4e51eae2011-02-25 19:05:48 +0100170static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200171{
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200173 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200174
Szymon Janc4e51eae2011-02-25 19:05:48 +0100175 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200176
Szymon Janc4e51eae2011-02-25 19:05:48 +0100177 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200178 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100179 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200180
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200181 hci_del_off_timer(hdev);
182
Andre Guedes8c156c32011-07-07 10:30:36 -0300183 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200184
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200185 set_bit(HCI_MGMT, &hdev->flags);
186
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200187 memset(&rp, 0, sizeof(rp));
188
Johan Hedberga38528f2011-01-22 06:46:43 +0200189 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.powered = test_bit(HCI_UP, &hdev->flags);
192 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
193 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
194 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195
196 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200197 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 bacpy(&rp.bdaddr, &hdev->bdaddr);
204 memcpy(rp.features, hdev->features, 8);
205 memcpy(rp.dev_class, hdev->dev_class, 3);
206 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
207 rp.hci_ver = hdev->hci_ver;
208 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200209
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200210 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
211
Andre Guedes8c156c32011-07-07 10:30:36 -0300212 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200214
Szymon Janc4e51eae2011-02-25 19:05:48 +0100215 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200216}
217
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200218static void mgmt_pending_free(struct pending_cmd *cmd)
219{
220 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100221 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200222 kfree(cmd);
223}
224
Johan Hedberg366a0332011-02-19 12:05:55 -0300225static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
226 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200227{
228 struct pending_cmd *cmd;
229
230 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
231 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300232 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200233
234 cmd->opcode = opcode;
235 cmd->index = index;
236
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100237 cmd->param = kmalloc(len, GFP_ATOMIC);
238 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300240 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 }
242
Szymon Janc8fce6352011-03-22 13:12:20 +0100243 if (data)
244 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200245
246 cmd->sk = sk;
247 sock_hold(sk);
248
249 list_add(&cmd->list, &cmd_list);
250
Johan Hedberg366a0332011-02-19 12:05:55 -0300251 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200252}
253
254static void mgmt_pending_foreach(u16 opcode, int index,
255 void (*cb)(struct pending_cmd *cmd, void *data),
256 void *data)
257{
258 struct list_head *p, *n;
259
260 list_for_each_safe(p, n, &cmd_list) {
261 struct pending_cmd *cmd;
262
263 cmd = list_entry(p, struct pending_cmd, list);
264
265 if (cmd->opcode != opcode)
266 continue;
267
268 if (index >= 0 && cmd->index != index)
269 continue;
270
271 cb(cmd, data);
272 }
273}
274
275static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
276{
277 struct list_head *p;
278
279 list_for_each(p, &cmd_list) {
280 struct pending_cmd *cmd;
281
282 cmd = list_entry(p, struct pending_cmd, list);
283
284 if (cmd->opcode != opcode)
285 continue;
286
287 if (index >= 0 && cmd->index != index)
288 continue;
289
290 return cmd;
291 }
292
293 return NULL;
294}
295
Johan Hedberga664b5b2011-02-19 12:06:02 -0300296static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200298 list_del(&cmd->list);
299 mgmt_pending_free(cmd);
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200304 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300307 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
309 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Janc4e51eae2011-02-25 19:05:48 +0100311 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100313 if (len != sizeof(*cp))
314 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
315
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100318 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
Andre Guedes8c156c32011-07-07 10:30:36 -0300320 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321
322 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200323 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100324 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200325 goto failed;
326 }
327
Szymon Janc4e51eae2011-02-25 19:05:48 +0100328 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
329 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330 goto failed;
331 }
332
Szymon Janc4e51eae2011-02-25 19:05:48 +0100333 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 if (!cmd) {
335 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300337 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338
Johan Hedberg72a734e2010-12-30 00:38:22 +0200339 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340 queue_work(hdev->workqueue, &hdev->power_on);
341 else
342 queue_work(hdev->workqueue, &hdev->power_off);
343
Johan Hedberg366a0332011-02-19 12:05:55 -0300344 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345
346failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300347 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300349 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350}
351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
353 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200355 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 u8 scan;
359 int err;
360
361 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Janc4e51eae2011-02-25 19:05:48 +0100363 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100365 if (len != sizeof(*cp))
366 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
367
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100370 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
Andre Guedes8c156c32011-07-07 10:30:36 -0300372 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373
374 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100375 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 goto failed;
377 }
378
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
380 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
381 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 goto failed;
383 }
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100387 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388 goto failed;
389 }
390
Szymon Janc4e51eae2011-02-25 19:05:48 +0100391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300392 if (!cmd) {
393 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396
397 scan = SCAN_PAGE;
398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400 scan |= SCAN_INQUIRY;
401
402 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
403 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300404 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200405
406failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300407 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200408 hci_dev_put(hdev);
409
410 return err;
411}
412
Szymon Janc4e51eae2011-02-25 19:05:48 +0100413static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
414 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200416 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300418 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419 u8 scan;
420 int err;
421
422 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423
Szymon Janc4e51eae2011-02-25 19:05:48 +0100424 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200425
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100426 if (len != sizeof(*cp))
427 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
428
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100431 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200432
Andre Guedes8c156c32011-07-07 10:30:36 -0300433 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200434
435 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100436 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437 goto failed;
438 }
439
Szymon Janc4e51eae2011-02-25 19:05:48 +0100440 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
441 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
442 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200443 goto failed;
444 }
445
Johan Hedberg72a734e2010-12-30 00:38:22 +0200446 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100447 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448 goto failed;
449 }
450
Szymon Janc4e51eae2011-02-25 19:05:48 +0100451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300452 if (!cmd) {
453 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300455 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456
Johan Hedberg72a734e2010-12-30 00:38:22 +0200457 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200458 scan = SCAN_PAGE;
459 else
460 scan = 0;
461
462 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
463 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300464 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200465
466failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300467 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200468 hci_dev_put(hdev);
469
470 return err;
471}
472
Szymon Janc4e51eae2011-02-25 19:05:48 +0100473static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
474 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200475{
476 struct sk_buff *skb;
477 struct mgmt_hdr *hdr;
478
479 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
480 if (!skb)
481 return -ENOMEM;
482
483 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
484
485 hdr = (void *) skb_put(skb, sizeof(*hdr));
486 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100487 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200488 hdr->len = cpu_to_le16(data_len);
489
Szymon Janc4e51eae2011-02-25 19:05:48 +0100490 if (data)
491 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200492
493 hci_send_to_sock(NULL, skb, skip_sk);
494 kfree_skb(skb);
495
496 return 0;
497}
498
Johan Hedberg053f0212011-01-26 13:07:10 +0200499static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
500{
Johan Hedberga38528f2011-01-22 06:46:43 +0200501 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200502
Johan Hedberga38528f2011-01-22 06:46:43 +0200503 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200504
Szymon Janc4e51eae2011-02-25 19:05:48 +0100505 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200506}
507
Szymon Janc4e51eae2011-02-25 19:05:48 +0100508static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
509 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200510{
511 struct mgmt_mode *cp, ev;
512 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200513 int err;
514
515 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200516
Szymon Janc4e51eae2011-02-25 19:05:48 +0100517 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200518
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100519 if (len != sizeof(*cp))
520 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
521
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100524 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200525
Andre Guedes8c156c32011-07-07 10:30:36 -0300526 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200527
528 if (cp->val)
529 set_bit(HCI_PAIRABLE, &hdev->flags);
530 else
531 clear_bit(HCI_PAIRABLE, &hdev->flags);
532
Szymon Janc4e51eae2011-02-25 19:05:48 +0100533 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200534 if (err < 0)
535 goto failed;
536
Johan Hedbergc542a062011-01-26 13:11:03 +0200537 ev.val = cp->val;
538
Szymon Janc4e51eae2011-02-25 19:05:48 +0100539 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200540
541failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300542 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200543 hci_dev_put(hdev);
544
545 return err;
546}
547
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548#define EIR_FLAGS 0x01 /* flags */
549#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
550#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
551#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
552#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
553#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
554#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
555#define EIR_NAME_SHORT 0x08 /* shortened local name */
556#define EIR_NAME_COMPLETE 0x09 /* complete local name */
557#define EIR_TX_POWER 0x0A /* transmit power level */
558#define EIR_DEVICE_ID 0x10 /* device ID */
559
560#define PNP_INFO_SVCLASS_ID 0x1200
561
562static u8 bluetooth_base_uuid[] = {
563 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
564 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565};
566
567static u16 get_uuid16(u8 *uuid128)
568{
569 u32 val;
570 int i;
571
572 for (i = 0; i < 12; i++) {
573 if (bluetooth_base_uuid[i] != uuid128[i])
574 return 0;
575 }
576
577 memcpy(&val, &uuid128[12], 4);
578
579 val = le32_to_cpu(val);
580 if (val > 0xffff)
581 return 0;
582
583 return (u16) val;
584}
585
586static void create_eir(struct hci_dev *hdev, u8 *data)
587{
588 u8 *ptr = data;
589 u16 eir_len = 0;
590 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
591 int i, truncated = 0;
592 struct list_head *p;
593 size_t name_len;
594
595 name_len = strlen(hdev->dev_name);
596
597 if (name_len > 0) {
598 /* EIR Data type */
599 if (name_len > 48) {
600 name_len = 48;
601 ptr[1] = EIR_NAME_SHORT;
602 } else
603 ptr[1] = EIR_NAME_COMPLETE;
604
605 /* EIR Data length */
606 ptr[0] = name_len + 1;
607
608 memcpy(ptr + 2, hdev->dev_name, name_len);
609
610 eir_len += (name_len + 2);
611 ptr += (name_len + 2);
612 }
613
614 memset(uuid16_list, 0, sizeof(uuid16_list));
615
616 /* Group all UUID16 types */
617 list_for_each(p, &hdev->uuids) {
618 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
619 u16 uuid16;
620
621 uuid16 = get_uuid16(uuid->uuid);
622 if (uuid16 == 0)
623 return;
624
625 if (uuid16 < 0x1100)
626 continue;
627
628 if (uuid16 == PNP_INFO_SVCLASS_ID)
629 continue;
630
631 /* Stop if not enough space to put next UUID */
632 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
633 truncated = 1;
634 break;
635 }
636
637 /* Check for duplicates */
638 for (i = 0; uuid16_list[i] != 0; i++)
639 if (uuid16_list[i] == uuid16)
640 break;
641
642 if (uuid16_list[i] == 0) {
643 uuid16_list[i] = uuid16;
644 eir_len += sizeof(u16);
645 }
646 }
647
648 if (uuid16_list[0] != 0) {
649 u8 *length = ptr;
650
651 /* EIR Data type */
652 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
653
654 ptr += 2;
655 eir_len += 2;
656
657 for (i = 0; uuid16_list[i] != 0; i++) {
658 *ptr++ = (uuid16_list[i] & 0x00ff);
659 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
660 }
661
662 /* EIR Data length */
663 *length = (i * sizeof(u16)) + 1;
664 }
665}
666
667static int update_eir(struct hci_dev *hdev)
668{
669 struct hci_cp_write_eir cp;
670
671 if (!(hdev->features[6] & LMP_EXT_INQ))
672 return 0;
673
674 if (hdev->ssp_mode == 0)
675 return 0;
676
677 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
678 return 0;
679
680 memset(&cp, 0, sizeof(cp));
681
682 create_eir(hdev, cp.data);
683
684 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
685 return 0;
686
687 memcpy(hdev->eir, cp.data, sizeof(cp.data));
688
689 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
690}
691
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200692static u8 get_service_classes(struct hci_dev *hdev)
693{
694 struct list_head *p;
695 u8 val = 0;
696
697 list_for_each(p, &hdev->uuids) {
698 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
699
700 val |= uuid->svc_hint;
701 }
702
703 return val;
704}
705
706static int update_class(struct hci_dev *hdev)
707{
708 u8 cod[3];
709
710 BT_DBG("%s", hdev->name);
711
712 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
713 return 0;
714
715 cod[0] = hdev->minor_class;
716 cod[1] = hdev->major_class;
717 cod[2] = get_service_classes(hdev);
718
719 if (memcmp(cod, hdev->dev_class, 3) == 0)
720 return 0;
721
722 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
723}
724
Szymon Janc4e51eae2011-02-25 19:05:48 +0100725static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200726{
727 struct mgmt_cp_add_uuid *cp;
728 struct hci_dev *hdev;
729 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730 int err;
731
732 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200733
Szymon Janc4e51eae2011-02-25 19:05:48 +0100734 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200735
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100736 if (len != sizeof(*cp))
737 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
738
Szymon Janc4e51eae2011-02-25 19:05:48 +0100739 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200740 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100741 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200742
Andre Guedes8c156c32011-07-07 10:30:36 -0300743 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200744
745 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
746 if (!uuid) {
747 err = -ENOMEM;
748 goto failed;
749 }
750
751 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200752 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200753
754 list_add(&uuid->list, &hdev->uuids);
755
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200756 err = update_class(hdev);
757 if (err < 0)
758 goto failed;
759
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760 err = update_eir(hdev);
761 if (err < 0)
762 goto failed;
763
Szymon Janc4e51eae2011-02-25 19:05:48 +0100764 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200765
766failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300767 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768 hci_dev_put(hdev);
769
770 return err;
771}
772
Szymon Janc4e51eae2011-02-25 19:05:48 +0100773static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200774{
775 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100776 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777 struct hci_dev *hdev;
778 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 +0200779 int err, found;
780
781 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782
Szymon Janc4e51eae2011-02-25 19:05:48 +0100783 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200784
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100785 if (len != sizeof(*cp))
786 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
787
Szymon Janc4e51eae2011-02-25 19:05:48 +0100788 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200789 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100790 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200791
Andre Guedes8c156c32011-07-07 10:30:36 -0300792 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200793
794 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
795 err = hci_uuids_clear(hdev);
796 goto unlock;
797 }
798
799 found = 0;
800
801 list_for_each_safe(p, n, &hdev->uuids) {
802 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
803
804 if (memcmp(match->uuid, cp->uuid, 16) != 0)
805 continue;
806
807 list_del(&match->list);
808 found++;
809 }
810
811 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200813 goto unlock;
814 }
815
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200816 err = update_class(hdev);
817 if (err < 0)
818 goto unlock;
819
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300820 err = update_eir(hdev);
821 if (err < 0)
822 goto unlock;
823
Szymon Janc4e51eae2011-02-25 19:05:48 +0100824 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200825
826unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300827 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200828 hci_dev_put(hdev);
829
830 return err;
831}
832
Szymon Janc4e51eae2011-02-25 19:05:48 +0100833static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
834 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200835{
836 struct hci_dev *hdev;
837 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838 int err;
839
840 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200841
Szymon Janc4e51eae2011-02-25 19:05:48 +0100842 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200843
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100844 if (len != sizeof(*cp))
845 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
846
Szymon Janc4e51eae2011-02-25 19:05:48 +0100847 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200848 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100849 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200850
Andre Guedes8c156c32011-07-07 10:30:36 -0300851 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200852
853 hdev->major_class = cp->major;
854 hdev->minor_class = cp->minor;
855
856 err = update_class(hdev);
857
858 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100859 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200860
Andre Guedes8c156c32011-07-07 10:30:36 -0300861 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200862 hci_dev_put(hdev);
863
864 return err;
865}
866
Szymon Janc4e51eae2011-02-25 19:05:48 +0100867static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
868 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200869{
870 struct hci_dev *hdev;
871 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872 int err;
873
874 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100876 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100877 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100878
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200880 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100881 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200882
Andre Guedes8c156c32011-07-07 10:30:36 -0300883 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200884
Szymon Janc4e51eae2011-02-25 19:05:48 +0100885 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200886
887 if (cp->enable) {
888 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
889 err = 0;
890 } else {
891 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
892 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300893 if (err == 0)
894 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200895 }
896
897 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100898 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
899 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900
Andre Guedes8c156c32011-07-07 10:30:36 -0300901 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 hci_dev_put(hdev);
903
904 return err;
905}
906
Szymon Janc4e51eae2011-02-25 19:05:48 +0100907static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200908{
909 struct hci_dev *hdev;
910 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300912 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200913
914 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100915
916 if (len < sizeof(*cp))
917 return -EINVAL;
918
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200919 key_count = get_unaligned_le16(&cp->key_count);
920
921 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300922 if (expected_len != len) {
923 BT_ERR("load_keys: expected %u bytes, got %u bytes",
924 len, expected_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200925 return -EINVAL;
926 }
927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200929 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933 key_count);
934
Andre Guedes8c156c32011-07-07 10:30:36 -0300935 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200936
937 hci_link_keys_clear(hdev);
938
939 set_bit(HCI_LINK_KEYS, &hdev->flags);
940
941 if (cp->debug_keys)
942 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
943 else
944 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
945
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300946 for (i = 0; i < key_count; i++) {
947 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200948
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700949 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950 key->pin_len);
951 }
952
Andre Guedes8c156c32011-07-07 10:30:36 -0300953 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954 hci_dev_put(hdev);
955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300956 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957}
958
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200960{
961 struct hci_dev *hdev;
962 struct mgmt_cp_remove_key *cp;
963 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200964 int err;
965
966 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100968 if (len != sizeof(*cp))
969 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
970
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200972 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974
Andre Guedes8c156c32011-07-07 10:30:36 -0300975 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200976
977 err = hci_remove_link_key(hdev, &cp->bdaddr);
978 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200980 goto unlock;
981 }
982
983 err = 0;
984
985 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
986 goto unlock;
987
988 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
989 if (conn) {
990 struct hci_cp_disconnect dc;
991
992 put_unaligned_le16(conn->handle, &dc.handle);
993 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400994 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200995 }
996
997unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300998 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200999 hci_dev_put(hdev);
1000
1001 return err;
1002}
1003
Szymon Janc4e51eae2011-02-25 19:05:48 +01001004static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001005{
1006 struct hci_dev *hdev;
1007 struct mgmt_cp_disconnect *cp;
1008 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001009 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001010 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001011 int err;
1012
1013 BT_DBG("");
1014
1015 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001016
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001017 if (len != sizeof(*cp))
1018 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1019
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001021 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023
Andre Guedes8c156c32011-07-07 10:30:36 -03001024 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025
1026 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 goto failed;
1029 }
1030
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1032 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001033 goto failed;
1034 }
1035
1036 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001037 if (!conn)
1038 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1039
Johan Hedberg8962ee72011-01-20 12:40:27 +02001040 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 goto failed;
1043 }
1044
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001046 if (!cmd) {
1047 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001048 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001049 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001050
1051 put_unaligned_le16(conn->handle, &dc.handle);
1052 dc.reason = 0x13; /* Remote User Terminated Connection */
1053
1054 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1055 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001056 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057
1058failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001059 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001060 hci_dev_put(hdev);
1061
1062 return err;
1063}
1064
Szymon Janc8ce62842011-03-01 16:55:32 +01001065static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001066{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001067 struct mgmt_rp_get_connections *rp;
1068 struct hci_dev *hdev;
1069 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001070 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001071 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001072 int i, err;
1073
1074 BT_DBG("");
1075
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001079
Andre Guedes8c156c32011-07-07 10:30:36 -03001080 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001081
1082 count = 0;
1083 list_for_each(p, &hdev->conn_hash.list) {
1084 count++;
1085 }
1086
Johan Hedberga38528f2011-01-22 06:46:43 +02001087 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1088 rp = kmalloc(rp_len, GFP_ATOMIC);
1089 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001090 err = -ENOMEM;
1091 goto unlock;
1092 }
1093
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 put_unaligned_le16(count, &rp->conn_count);
1095
Johan Hedberg2784eb42011-01-21 13:56:35 +02001096 i = 0;
1097 list_for_each(p, &hdev->conn_hash.list) {
1098 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1099
1100 bacpy(&rp->conn[i++], &c->dst);
1101 }
1102
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104
1105unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001106 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001107 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001108 hci_dev_put(hdev);
1109 return err;
1110}
1111
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001112static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1113 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1114{
1115 struct pending_cmd *cmd;
1116 int err;
1117
1118 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1119 sizeof(*cp));
1120 if (!cmd)
1121 return -ENOMEM;
1122
1123 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1124 &cp->bdaddr);
1125 if (err < 0)
1126 mgmt_pending_remove(cmd);
1127
1128 return err;
1129}
1130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1132 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001133{
1134 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001135 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001137 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001139 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001140 int err;
1141
1142 BT_DBG("");
1143
1144 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146 if (len != sizeof(*cp))
1147 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152
Andre Guedes8c156c32011-07-07 10:30:36 -03001153 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154
1155 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001157 goto failed;
1158 }
1159
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001160 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1161 if (!conn) {
1162 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1163 goto failed;
1164 }
1165
1166 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1167 bacpy(&ncp.bdaddr, &cp->bdaddr);
1168
1169 BT_ERR("PIN code is not 16 bytes long");
1170
1171 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1172 if (err >= 0)
1173 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1174 EINVAL);
1175
1176 goto failed;
1177 }
1178
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 if (!cmd) {
1181 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001183 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184
1185 bacpy(&reply.bdaddr, &cp->bdaddr);
1186 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001187 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188
1189 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1190 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001191 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001192
1193failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001194 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 hci_dev_put(hdev);
1196
1197 return err;
1198}
1199
Szymon Janc4e51eae2011-02-25 19:05:48 +01001200static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1201 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202{
1203 struct hci_dev *hdev;
1204 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205 int err;
1206
1207 BT_DBG("");
1208
1209 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001211 if (len != sizeof(*cp))
1212 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1213 EINVAL);
1214
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001216 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1218 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219
Andre Guedes8c156c32011-07-07 10:30:36 -03001220 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221
1222 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001223 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1224 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001225 goto failed;
1226 }
1227
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001228 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001229
1230failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001231 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232 hci_dev_put(hdev);
1233
1234 return err;
1235}
1236
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1238 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001239{
1240 struct hci_dev *hdev;
1241 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001242
1243 BT_DBG("");
1244
1245 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001246
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001247 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001248 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001249
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001251 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253
Andre Guedes8c156c32011-07-07 10:30:36 -03001254 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255
1256 hdev->io_capability = cp->io_capability;
1257
1258 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001259 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260
Andre Guedes8c156c32011-07-07 10:30:36 -03001261 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001262 hci_dev_put(hdev);
1263
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265}
1266
Johan Hedberge9a416b2011-02-19 12:05:56 -03001267static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1268{
1269 struct hci_dev *hdev = conn->hdev;
1270 struct list_head *p;
1271
1272 list_for_each(p, &cmd_list) {
1273 struct pending_cmd *cmd;
1274
1275 cmd = list_entry(p, struct pending_cmd, list);
1276
1277 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1278 continue;
1279
1280 if (cmd->index != hdev->id)
1281 continue;
1282
1283 if (cmd->user_data != conn)
1284 continue;
1285
1286 return cmd;
1287 }
1288
1289 return NULL;
1290}
1291
1292static void pairing_complete(struct pending_cmd *cmd, u8 status)
1293{
1294 struct mgmt_rp_pair_device rp;
1295 struct hci_conn *conn = cmd->user_data;
1296
Johan Hedberge9a416b2011-02-19 12:05:56 -03001297 bacpy(&rp.bdaddr, &conn->dst);
1298 rp.status = status;
1299
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001301
1302 /* So we don't get further callbacks for this connection */
1303 conn->connect_cfm_cb = NULL;
1304 conn->security_cfm_cb = NULL;
1305 conn->disconn_cfm_cb = NULL;
1306
1307 hci_conn_put(conn);
1308
Johan Hedberga664b5b2011-02-19 12:06:02 -03001309 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001310}
1311
1312static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1313{
1314 struct pending_cmd *cmd;
1315
1316 BT_DBG("status %u", status);
1317
1318 cmd = find_pairing(conn);
1319 if (!cmd) {
1320 BT_DBG("Unable to find a pending command");
1321 return;
1322 }
1323
1324 pairing_complete(cmd, status);
1325}
1326
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001328{
1329 struct hci_dev *hdev;
1330 struct mgmt_cp_pair_device *cp;
1331 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001332 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333 u8 sec_level, auth_type;
1334 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001335 int err;
1336
1337 BT_DBG("");
1338
1339 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001341 if (len != sizeof(*cp))
1342 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347
Andre Guedes8c156c32011-07-07 10:30:36 -03001348 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001350 sec_level = BT_SECURITY_MEDIUM;
1351 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001353 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001354 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001356 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1357 if (entry)
1358 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1359 auth_type);
1360 else
1361 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1362 auth_type);
1363
Ville Tervo30e76272011-02-22 16:10:53 -03001364 if (IS_ERR(conn)) {
1365 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001366 goto unlock;
1367 }
1368
1369 if (conn->connect_cfm_cb) {
1370 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001371 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 goto unlock;
1373 }
1374
Szymon Janc4e51eae2011-02-25 19:05:48 +01001375 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001376 if (!cmd) {
1377 err = -ENOMEM;
1378 hci_conn_put(conn);
1379 goto unlock;
1380 }
1381
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001382 /* For LE, just connecting isn't a proof that the pairing finished */
1383 if (!entry)
1384 conn->connect_cfm_cb = pairing_complete_cb;
1385
Johan Hedberge9a416b2011-02-19 12:05:56 -03001386 conn->security_cfm_cb = pairing_complete_cb;
1387 conn->disconn_cfm_cb = pairing_complete_cb;
1388 conn->io_capability = cp->io_cap;
1389 cmd->user_data = conn;
1390
1391 if (conn->state == BT_CONNECTED &&
1392 hci_conn_security(conn, sec_level, auth_type))
1393 pairing_complete(cmd, 0);
1394
1395 err = 0;
1396
1397unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001398 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001399 hci_dev_put(hdev);
1400
1401 return err;
1402}
1403
Szymon Janc4e51eae2011-02-25 19:05:48 +01001404static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1405 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001406{
1407 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001408 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001409 struct pending_cmd *cmd;
1410 struct hci_dev *hdev;
1411 int err;
1412
1413 BT_DBG("");
1414
Johan Hedberga5c29682011-02-19 12:05:57 -03001415 if (success) {
1416 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1417 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1418 } else {
1419 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1420 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1421 }
1422
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001423 if (len != sizeof(*cp))
1424 return cmd_status(sk, index, mgmt_op, EINVAL);
1425
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001427 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001429
Andre Guedes8c156c32011-07-07 10:30:36 -03001430 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001431
Johan Hedberga5c29682011-02-19 12:05:57 -03001432 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001433 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001434 goto failed;
1435 }
1436
Szymon Janc4e51eae2011-02-25 19:05:48 +01001437 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001438 if (!cmd) {
1439 err = -ENOMEM;
1440 goto failed;
1441 }
1442
1443 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001444 if (err < 0)
1445 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001446
1447failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001448 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001449 hci_dev_put(hdev);
1450
1451 return err;
1452}
1453
Johan Hedbergb312b1612011-03-16 14:29:37 +02001454static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1455 u16 len)
1456{
1457 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1458 struct hci_cp_write_local_name hci_cp;
1459 struct hci_dev *hdev;
1460 struct pending_cmd *cmd;
1461 int err;
1462
1463 BT_DBG("");
1464
1465 if (len != sizeof(*mgmt_cp))
1466 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1467
1468 hdev = hci_dev_get(index);
1469 if (!hdev)
1470 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1471
Andre Guedes8c156c32011-07-07 10:30:36 -03001472 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001473
1474 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1475 if (!cmd) {
1476 err = -ENOMEM;
1477 goto failed;
1478 }
1479
1480 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1481 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1482 &hci_cp);
1483 if (err < 0)
1484 mgmt_pending_remove(cmd);
1485
1486failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001487 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001488 hci_dev_put(hdev);
1489
1490 return err;
1491}
1492
Szymon Jancc35938b2011-03-22 13:12:21 +01001493static int read_local_oob_data(struct sock *sk, u16 index)
1494{
1495 struct hci_dev *hdev;
1496 struct pending_cmd *cmd;
1497 int err;
1498
1499 BT_DBG("hci%u", index);
1500
1501 hdev = hci_dev_get(index);
1502 if (!hdev)
1503 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1504 ENODEV);
1505
Andre Guedes8c156c32011-07-07 10:30:36 -03001506 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001507
1508 if (!test_bit(HCI_UP, &hdev->flags)) {
1509 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1510 ENETDOWN);
1511 goto unlock;
1512 }
1513
1514 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1515 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1516 EOPNOTSUPP);
1517 goto unlock;
1518 }
1519
1520 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1521 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1522 goto unlock;
1523 }
1524
1525 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1526 if (!cmd) {
1527 err = -ENOMEM;
1528 goto unlock;
1529 }
1530
1531 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1532 if (err < 0)
1533 mgmt_pending_remove(cmd);
1534
1535unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001536 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001537 hci_dev_put(hdev);
1538
1539 return err;
1540}
1541
Szymon Janc2763eda2011-03-22 13:12:22 +01001542static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1543 u16 len)
1544{
1545 struct hci_dev *hdev;
1546 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1547 int err;
1548
1549 BT_DBG("hci%u ", index);
1550
1551 if (len != sizeof(*cp))
1552 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1553 EINVAL);
1554
1555 hdev = hci_dev_get(index);
1556 if (!hdev)
1557 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1558 ENODEV);
1559
Andre Guedes8c156c32011-07-07 10:30:36 -03001560 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001561
1562 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1563 cp->randomizer);
1564 if (err < 0)
1565 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1566 else
1567 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1568 0);
1569
Andre Guedes8c156c32011-07-07 10:30:36 -03001570 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001571 hci_dev_put(hdev);
1572
1573 return err;
1574}
1575
1576static int remove_remote_oob_data(struct sock *sk, u16 index,
1577 unsigned char *data, u16 len)
1578{
1579 struct hci_dev *hdev;
1580 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1581 int err;
1582
1583 BT_DBG("hci%u ", index);
1584
1585 if (len != sizeof(*cp))
1586 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1587 EINVAL);
1588
1589 hdev = hci_dev_get(index);
1590 if (!hdev)
1591 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1592 ENODEV);
1593
Andre Guedes8c156c32011-07-07 10:30:36 -03001594 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001595
1596 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1597 if (err < 0)
1598 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1599 -err);
1600 else
1601 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1602 NULL, 0);
1603
Andre Guedes8c156c32011-07-07 10:30:36 -03001604 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001605 hci_dev_put(hdev);
1606
1607 return err;
1608}
1609
Johan Hedberg14a53662011-04-27 10:29:56 -04001610static int start_discovery(struct sock *sk, u16 index)
1611{
1612 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1613 struct hci_cp_inquiry cp;
1614 struct pending_cmd *cmd;
1615 struct hci_dev *hdev;
1616 int err;
1617
1618 BT_DBG("hci%u", index);
1619
1620 hdev = hci_dev_get(index);
1621 if (!hdev)
1622 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1623
1624 hci_dev_lock_bh(hdev);
1625
1626 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1627 if (!cmd) {
1628 err = -ENOMEM;
1629 goto failed;
1630 }
1631
1632 memset(&cp, 0, sizeof(cp));
1633 memcpy(&cp.lap, lap, 3);
1634 cp.length = 0x08;
1635 cp.num_rsp = 0x00;
1636
1637 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1638 if (err < 0)
1639 mgmt_pending_remove(cmd);
1640
1641failed:
1642 hci_dev_unlock_bh(hdev);
1643 hci_dev_put(hdev);
1644
1645 return err;
1646}
1647
1648static int stop_discovery(struct sock *sk, u16 index)
1649{
1650 struct hci_dev *hdev;
1651 struct pending_cmd *cmd;
1652 int err;
1653
1654 BT_DBG("hci%u", index);
1655
1656 hdev = hci_dev_get(index);
1657 if (!hdev)
1658 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1659
1660 hci_dev_lock_bh(hdev);
1661
1662 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1663 if (!cmd) {
1664 err = -ENOMEM;
1665 goto failed;
1666 }
1667
1668 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1669 if (err < 0)
1670 mgmt_pending_remove(cmd);
1671
1672failed:
1673 hci_dev_unlock_bh(hdev);
1674 hci_dev_put(hdev);
1675
1676 return err;
1677}
1678
Antti Julku7fbec222011-06-15 12:01:15 +03001679static int block_device(struct sock *sk, u16 index, unsigned char *data,
1680 u16 len)
1681{
1682 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001683 struct pending_cmd *cmd;
1684 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001685 int err;
1686
1687 BT_DBG("hci%u", index);
1688
Antti Julku7fbec222011-06-15 12:01:15 +03001689 if (len != sizeof(*cp))
1690 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1691 EINVAL);
1692
1693 hdev = hci_dev_get(index);
1694 if (!hdev)
1695 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1696 ENODEV);
1697
Antti Julku5e762442011-08-25 16:48:02 +03001698 hci_dev_lock_bh(hdev);
1699
1700 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1701 if (!cmd) {
1702 err = -ENOMEM;
1703 goto failed;
1704 }
1705
Antti Julku7fbec222011-06-15 12:01:15 +03001706 err = hci_blacklist_add(hdev, &cp->bdaddr);
1707
1708 if (err < 0)
1709 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1710 else
1711 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1712 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001713
1714 mgmt_pending_remove(cmd);
1715
1716failed:
1717 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001718 hci_dev_put(hdev);
1719
1720 return err;
1721}
1722
1723static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1724 u16 len)
1725{
1726 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001727 struct pending_cmd *cmd;
1728 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001729 int err;
1730
1731 BT_DBG("hci%u", index);
1732
Antti Julku7fbec222011-06-15 12:01:15 +03001733 if (len != sizeof(*cp))
1734 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1735 EINVAL);
1736
1737 hdev = hci_dev_get(index);
1738 if (!hdev)
1739 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1740 ENODEV);
1741
Antti Julku5e762442011-08-25 16:48:02 +03001742 hci_dev_lock_bh(hdev);
1743
1744 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1745 if (!cmd) {
1746 err = -ENOMEM;
1747 goto failed;
1748 }
1749
Antti Julku7fbec222011-06-15 12:01:15 +03001750 err = hci_blacklist_del(hdev, &cp->bdaddr);
1751
1752 if (err < 0)
1753 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1754 else
1755 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1756 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001757
1758 mgmt_pending_remove(cmd);
1759
1760failed:
1761 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001762 hci_dev_put(hdev);
1763
1764 return err;
1765}
1766
Antti Julkuf6422ec2011-06-22 13:11:56 +03001767static int set_fast_connectable(struct sock *sk, u16 index,
1768 unsigned char *data, u16 len)
1769{
1770 struct hci_dev *hdev;
1771 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1772 struct hci_cp_write_page_scan_activity acp;
1773 u8 type;
1774 int err;
1775
1776 BT_DBG("hci%u", index);
1777
1778 if (len != sizeof(*cp))
1779 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1780 EINVAL);
1781
1782 hdev = hci_dev_get(index);
1783 if (!hdev)
1784 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1785 ENODEV);
1786
1787 hci_dev_lock(hdev);
1788
1789 if (cp->enable) {
1790 type = PAGE_SCAN_TYPE_INTERLACED;
1791 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1792 } else {
1793 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1794 acp.interval = 0x0800; /* default 1.28 sec page scan */
1795 }
1796
1797 acp.window = 0x0012; /* default 11.25 msec page scan window */
1798
1799 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1800 sizeof(acp), &acp);
1801 if (err < 0) {
1802 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1803 -err);
1804 goto done;
1805 }
1806
1807 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1808 if (err < 0) {
1809 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1810 -err);
1811 goto done;
1812 }
1813
1814 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1815 NULL, 0);
1816done:
1817 hci_dev_unlock(hdev);
1818 hci_dev_put(hdev);
1819
1820 return err;
1821}
1822
Johan Hedberg03811012010-12-08 00:21:06 +02001823int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1824{
1825 unsigned char *buf;
1826 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001827 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001828 int err;
1829
1830 BT_DBG("got %zu bytes", msglen);
1831
1832 if (msglen < sizeof(*hdr))
1833 return -EINVAL;
1834
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001835 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001836 if (!buf)
1837 return -ENOMEM;
1838
1839 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1840 err = -EFAULT;
1841 goto done;
1842 }
1843
1844 hdr = (struct mgmt_hdr *) buf;
1845 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001847 len = get_unaligned_le16(&hdr->len);
1848
1849 if (len != msglen - sizeof(*hdr)) {
1850 err = -EINVAL;
1851 goto done;
1852 }
1853
1854 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001855 case MGMT_OP_READ_VERSION:
1856 err = read_version(sk);
1857 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001858 case MGMT_OP_READ_INDEX_LIST:
1859 err = read_index_list(sk);
1860 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001861 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001863 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001864 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001866 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001867 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001869 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001870 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001872 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001873 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001875 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001878 break;
1879 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001881 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001884 break;
1885 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001887 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890 break;
1891 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001896 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001897 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001898 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001899 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001902 break;
1903 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001908 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001914 break;
1915 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001916 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001918 case MGMT_OP_SET_LOCAL_NAME:
1919 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1920 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001921 case MGMT_OP_READ_LOCAL_OOB_DATA:
1922 err = read_local_oob_data(sk, index);
1923 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001924 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1925 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1926 break;
1927 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1928 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1929 len);
1930 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001931 case MGMT_OP_START_DISCOVERY:
1932 err = start_discovery(sk, index);
1933 break;
1934 case MGMT_OP_STOP_DISCOVERY:
1935 err = stop_discovery(sk, index);
1936 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001937 case MGMT_OP_BLOCK_DEVICE:
1938 err = block_device(sk, index, buf + sizeof(*hdr), len);
1939 break;
1940 case MGMT_OP_UNBLOCK_DEVICE:
1941 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1942 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001943 case MGMT_OP_SET_FAST_CONNECTABLE:
1944 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1945 len);
1946 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001947 default:
1948 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001949 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001950 break;
1951 }
1952
Johan Hedberge41d8b42010-12-13 21:07:03 +02001953 if (err < 0)
1954 goto done;
1955
Johan Hedberg03811012010-12-08 00:21:06 +02001956 err = msglen;
1957
1958done:
1959 kfree(buf);
1960 return err;
1961}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001962
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001963int mgmt_index_added(u16 index)
1964{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001965 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001966}
1967
1968int mgmt_index_removed(u16 index)
1969{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001970 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001971}
1972
Johan Hedberg73f22f62010-12-29 16:00:25 +02001973struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001974 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001975 struct sock *sk;
1976};
1977
Johan Hedberg72a734e2010-12-30 00:38:22 +02001978static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001979{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001980 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001981 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982
Johan Hedberg72a734e2010-12-30 00:38:22 +02001983 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001984 return;
1985
Johan Hedberg053f0212011-01-26 13:07:10 +02001986 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001987
1988 list_del(&cmd->list);
1989
1990 if (match->sk == NULL) {
1991 match->sk = cmd->sk;
1992 sock_hold(match->sk);
1993 }
1994
1995 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001996}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001997
1998int mgmt_powered(u16 index, u8 powered)
1999{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002000 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002001 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002002 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002003
Johan Hedberg72a734e2010-12-30 00:38:22 +02002004 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002005
Johan Hedberg72a734e2010-12-30 00:38:22 +02002006 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002007
Szymon Janc4e51eae2011-02-25 19:05:48 +01002008 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002009
2010 if (match.sk)
2011 sock_put(match.sk);
2012
2013 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002014}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002015
Johan Hedberg73f22f62010-12-29 16:00:25 +02002016int mgmt_discoverable(u16 index, u8 discoverable)
2017{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002018 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019 struct cmd_lookup match = { discoverable, NULL };
2020 int ret;
2021
Szymon Jancb8534e02011-03-01 16:55:34 +01002022 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002023
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002025
Szymon Janc4e51eae2011-02-25 19:05:48 +01002026 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2027 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002028
2029 if (match.sk)
2030 sock_put(match.sk);
2031
2032 return ret;
2033}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002034
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002035int mgmt_connectable(u16 index, u8 connectable)
2036{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002037 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002038 struct cmd_lookup match = { connectable, NULL };
2039 int ret;
2040
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002042
Johan Hedberg72a734e2010-12-30 00:38:22 +02002043 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002044
Szymon Janc4e51eae2011-02-25 19:05:48 +01002045 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002046
2047 if (match.sk)
2048 sock_put(match.sk);
2049
2050 return ret;
2051}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002052
Johan Hedberg4df378a2011-04-28 11:29:03 -07002053int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002054{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002055 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002056
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002057 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002059 ev.store_hint = persistent;
2060 bacpy(&ev.key.bdaddr, &key->bdaddr);
2061 ev.key.type = key->type;
2062 memcpy(ev.key.val, key->val, 16);
2063 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002065 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002066}
Johan Hedbergf7520542011-01-20 12:34:39 +02002067
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002068int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002069{
2070 struct mgmt_ev_connected ev;
2071
Johan Hedbergf7520542011-01-20 12:34:39 +02002072 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002073 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002074
Szymon Janc4e51eae2011-02-25 19:05:48 +01002075 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002076}
2077
Johan Hedberg8962ee72011-01-20 12:40:27 +02002078static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2079{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002080 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002081 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002082 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002083
Johan Hedberga38528f2011-01-22 06:46:43 +02002084 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002085
Szymon Janc4e51eae2011-02-25 19:05:48 +01002086 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002087
2088 *sk = cmd->sk;
2089 sock_hold(*sk);
2090
Johan Hedberga664b5b2011-02-19 12:06:02 -03002091 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002092}
2093
Johan Hedbergf7520542011-01-20 12:34:39 +02002094int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2095{
2096 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002097 struct sock *sk = NULL;
2098 int err;
2099
2100 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002101
Johan Hedbergf7520542011-01-20 12:34:39 +02002102 bacpy(&ev.bdaddr, bdaddr);
2103
Szymon Janc4e51eae2011-02-25 19:05:48 +01002104 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002105
2106 if (sk)
2107 sock_put(sk);
2108
2109 return err;
2110}
2111
2112int mgmt_disconnect_failed(u16 index)
2113{
2114 struct pending_cmd *cmd;
2115 int err;
2116
2117 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2118 if (!cmd)
2119 return -ENOENT;
2120
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002122
Johan Hedberga664b5b2011-02-19 12:06:02 -03002123 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002124
2125 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002126}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002127
2128int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2129{
2130 struct mgmt_ev_connect_failed ev;
2131
Johan Hedberg17d5c042011-01-22 06:09:08 +02002132 bacpy(&ev.bdaddr, bdaddr);
2133 ev.status = status;
2134
Szymon Janc4e51eae2011-02-25 19:05:48 +01002135 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002136}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002138int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002139{
2140 struct mgmt_ev_pin_code_request ev;
2141
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002143 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002144
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2146 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147}
2148
2149int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2150{
2151 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002152 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002153 int err;
2154
2155 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2156 if (!cmd)
2157 return -ENOENT;
2158
Johan Hedbergac56fb12011-02-19 12:05:59 -03002159 bacpy(&rp.bdaddr, bdaddr);
2160 rp.status = status;
2161
Szymon Janc4e51eae2011-02-25 19:05:48 +01002162 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2163 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002164
Johan Hedberga664b5b2011-02-19 12:06:02 -03002165 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002166
2167 return err;
2168}
2169
2170int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2171{
2172 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002173 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174 int err;
2175
2176 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2177 if (!cmd)
2178 return -ENOENT;
2179
Johan Hedbergac56fb12011-02-19 12:05:59 -03002180 bacpy(&rp.bdaddr, bdaddr);
2181 rp.status = status;
2182
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2184 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
Johan Hedberga664b5b2011-02-19 12:06:02 -03002186 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002187
2188 return err;
2189}
Johan Hedberga5c29682011-02-19 12:05:57 -03002190
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002191int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2192 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002193{
2194 struct mgmt_ev_user_confirm_request ev;
2195
2196 BT_DBG("hci%u", index);
2197
Johan Hedberga5c29682011-02-19 12:05:57 -03002198 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002199 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002200 put_unaligned_le32(value, &ev.value);
2201
Szymon Janc4e51eae2011-02-25 19:05:48 +01002202 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2203 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002204}
2205
2206static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2207 u8 opcode)
2208{
2209 struct pending_cmd *cmd;
2210 struct mgmt_rp_user_confirm_reply rp;
2211 int err;
2212
2213 cmd = mgmt_pending_find(opcode, index);
2214 if (!cmd)
2215 return -ENOENT;
2216
Johan Hedberga5c29682011-02-19 12:05:57 -03002217 bacpy(&rp.bdaddr, bdaddr);
2218 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002219 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002220
Johan Hedberga664b5b2011-02-19 12:06:02 -03002221 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002222
2223 return err;
2224}
2225
2226int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2227{
2228 return confirm_reply_complete(index, bdaddr, status,
2229 MGMT_OP_USER_CONFIRM_REPLY);
2230}
2231
Szymon Jancb8534e02011-03-01 16:55:34 +01002232int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002233{
2234 return confirm_reply_complete(index, bdaddr, status,
2235 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2236}
Johan Hedberg2a611692011-02-19 12:06:00 -03002237
2238int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2239{
2240 struct mgmt_ev_auth_failed ev;
2241
Johan Hedberg2a611692011-02-19 12:06:00 -03002242 bacpy(&ev.bdaddr, bdaddr);
2243 ev.status = status;
2244
Szymon Janc4e51eae2011-02-25 19:05:48 +01002245 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002246}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002247
2248int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2249{
2250 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002251 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002252 struct mgmt_cp_set_local_name ev;
2253 int err;
2254
2255 memset(&ev, 0, sizeof(ev));
2256 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2257
2258 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2259 if (!cmd)
2260 goto send_event;
2261
2262 if (status) {
2263 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2264 goto failed;
2265 }
2266
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002267 hdev = hci_dev_get(index);
2268 if (hdev) {
2269 hci_dev_lock_bh(hdev);
2270 update_eir(hdev);
2271 hci_dev_unlock_bh(hdev);
2272 hci_dev_put(hdev);
2273 }
2274
Johan Hedbergb312b1612011-03-16 14:29:37 +02002275 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2276 sizeof(ev));
2277 if (err < 0)
2278 goto failed;
2279
2280send_event:
2281 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2282 cmd ? cmd->sk : NULL);
2283
2284failed:
2285 if (cmd)
2286 mgmt_pending_remove(cmd);
2287 return err;
2288}
Szymon Jancc35938b2011-03-22 13:12:21 +01002289
2290int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2291 u8 status)
2292{
2293 struct pending_cmd *cmd;
2294 int err;
2295
2296 BT_DBG("hci%u status %u", index, status);
2297
2298 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2299 if (!cmd)
2300 return -ENOENT;
2301
2302 if (status) {
2303 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2304 EIO);
2305 } else {
2306 struct mgmt_rp_read_local_oob_data rp;
2307
2308 memcpy(rp.hash, hash, sizeof(rp.hash));
2309 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2310
2311 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2312 &rp, sizeof(rp));
2313 }
2314
2315 mgmt_pending_remove(cmd);
2316
2317 return err;
2318}
Johan Hedberge17acd42011-03-30 23:57:16 +03002319
2320int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2321 u8 *eir)
2322{
2323 struct mgmt_ev_device_found ev;
2324
2325 memset(&ev, 0, sizeof(ev));
2326
2327 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002328 ev.rssi = rssi;
2329
2330 if (eir)
2331 memcpy(ev.eir, eir, sizeof(ev.eir));
2332
Andre Guedesf8523592011-09-09 18:56:26 -03002333 if (dev_class)
2334 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2335
Johan Hedberge17acd42011-03-30 23:57:16 +03002336 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2337}
Johan Hedberga88a9652011-03-30 13:18:12 +03002338
2339int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2340{
2341 struct mgmt_ev_remote_name ev;
2342
2343 memset(&ev, 0, sizeof(ev));
2344
2345 bacpy(&ev.bdaddr, bdaddr);
2346 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2347
2348 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2349}
Johan Hedberg314b2382011-04-27 10:29:57 -04002350
2351int mgmt_discovering(u16 index, u8 discovering)
2352{
2353 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2354 sizeof(discovering), NULL);
2355}
Antti Julku5e762442011-08-25 16:48:02 +03002356
2357int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2358{
2359 struct pending_cmd *cmd;
2360 struct mgmt_ev_device_blocked ev;
2361
2362 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2363
2364 bacpy(&ev.bdaddr, bdaddr);
2365
2366 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2367 cmd ? cmd->sk : NULL);
2368}
2369
2370int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2371{
2372 struct pending_cmd *cmd;
2373 struct mgmt_ev_device_unblocked ev;
2374
2375 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2376
2377 bacpy(&ev.bdaddr, bdaddr);
2378
2379 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2380 cmd ? cmd->sk : NULL);
2381}