blob: 17c7fbbc12105494a533b8285f6807f5eefd167a [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
39 __u16 opcode;
40 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
Johannes Bergb5ad8b72011-06-01 08:54:45 +020046static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047
Szymon Janc4e51eae2011-02-25 19:05:48 +010048static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020049{
50 struct sk_buff *skb;
51 struct mgmt_hdr *hdr;
52 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030053 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
Szymon Janc34eb5252011-02-28 14:10:08 +010055 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020056
57 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
58 if (!skb)
59 return -ENOMEM;
60
61 hdr = (void *) skb_put(skb, sizeof(*hdr));
62
63 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010064 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020065 hdr->len = cpu_to_le16(sizeof(*ev));
66
67 ev = (void *) skb_put(skb, sizeof(*ev));
68 ev->status = status;
69 put_unaligned_le16(cmd, &ev->opcode);
70
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030071 err = sock_queue_rcv_skb(sk, skb);
72 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020073 kfree_skb(skb);
74
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030075 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076}
77
Szymon Janc4e51eae2011-02-25 19:05:48 +010078static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
79 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020080{
81 struct sk_buff *skb;
82 struct mgmt_hdr *hdr;
83 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030084 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020085
86 BT_DBG("sock %p", sk);
87
Johan Hedberga38528f2011-01-22 06:46:43 +020088 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020089 if (!skb)
90 return -ENOMEM;
91
92 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020093
Johan Hedberg02d98122010-12-13 21:07:04 +020094 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010095 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020096 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020097
Johan Hedberga38528f2011-01-22 06:46:43 +020098 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
99 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100100
101 if (rp)
102 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200103
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300104 err = sock_queue_rcv_skb(sk, skb);
105 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 kfree_skb(skb);
107
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300108 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200109}
110
Johan Hedberga38528f2011-01-22 06:46:43 +0200111static int read_version(struct sock *sk)
112{
113 struct mgmt_rp_read_version rp;
114
115 BT_DBG("sock %p", sk);
116
117 rp.version = MGMT_VERSION;
118 put_unaligned_le16(MGMT_REVISION, &rp.revision);
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
121 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200122}
123
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124static int read_index_list(struct sock *sk)
125{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126 struct mgmt_rp_read_index_list *rp;
127 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200128 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200131 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132
133 BT_DBG("sock %p", sk);
134
135 read_lock(&hci_dev_list_lock);
136
137 count = 0;
138 list_for_each(p, &hci_dev_list) {
139 count++;
140 }
141
Johan Hedberga38528f2011-01-22 06:46:43 +0200142 rp_len = sizeof(*rp) + (2 * count);
143 rp = kmalloc(rp_len, GFP_ATOMIC);
144 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100147 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(count, &rp->num_controllers);
150
151 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200152 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200153 hci_del_off_timer(d);
154
155 if (test_bit(HCI_SETUP, &d->flags))
156 continue;
157
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158 put_unaligned_le16(d->id, &rp->index[i++]);
159 BT_DBG("Added hci%u", d->id);
160 }
161
162 read_unlock(&hci_dev_list_lock);
163
Szymon Janc4e51eae2011-02-25 19:05:48 +0100164 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
165 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166
Johan Hedberga38528f2011-01-22 06:46:43 +0200167 kfree(rp);
168
169 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200170}
171
Szymon Janc4e51eae2011-02-25 19:05:48 +0100172static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200173{
Johan Hedberga38528f2011-01-22 06:46:43 +0200174 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200175 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200176
Szymon Janc4e51eae2011-02-25 19:05:48 +0100177 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200178
Szymon Janc4e51eae2011-02-25 19:05:48 +0100179 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200180 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100181 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200182
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200183 hci_del_off_timer(hdev);
184
Andre Guedes8c156c32011-07-07 10:30:36 -0300185 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200186
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200187 set_bit(HCI_MGMT, &hdev->flags);
188
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200189 memset(&rp, 0, sizeof(rp));
190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 rp.powered = test_bit(HCI_UP, &hdev->flags);
194 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
195 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
196 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197
198 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 bacpy(&rp.bdaddr, &hdev->bdaddr);
206 memcpy(rp.features, hdev->features, 8);
207 memcpy(rp.dev_class, hdev->dev_class, 3);
208 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
209 rp.hci_ver = hdev->hci_ver;
210 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200212 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
213
Andre Guedes8c156c32011-07-07 10:30:36 -0300214 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200216
Szymon Janc4e51eae2011-02-25 19:05:48 +0100217 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200218}
219
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220static void mgmt_pending_free(struct pending_cmd *cmd)
221{
222 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100223 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200224 kfree(cmd);
225}
226
Johan Hedberg366a0332011-02-19 12:05:55 -0300227static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
228 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200229{
230 struct pending_cmd *cmd;
231
232 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
233 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300234 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200235
236 cmd->opcode = opcode;
237 cmd->index = index;
238
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100239 cmd->param = kmalloc(len, GFP_ATOMIC);
240 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300242 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200243 }
244
Szymon Janc8fce6352011-03-22 13:12:20 +0100245 if (data)
246 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200247
248 cmd->sk = sk;
249 sock_hold(sk);
250
251 list_add(&cmd->list, &cmd_list);
252
Johan Hedberg366a0332011-02-19 12:05:55 -0300253 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200254}
255
256static void mgmt_pending_foreach(u16 opcode, int index,
257 void (*cb)(struct pending_cmd *cmd, void *data),
258 void *data)
259{
260 struct list_head *p, *n;
261
262 list_for_each_safe(p, n, &cmd_list) {
263 struct pending_cmd *cmd;
264
265 cmd = list_entry(p, struct pending_cmd, list);
266
Johan Hedbergb24752f2011-11-03 14:40:33 +0200267 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200268 continue;
269
270 if (index >= 0 && cmd->index != index)
271 continue;
272
273 cb(cmd, data);
274 }
275}
276
277static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
278{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200279 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200280
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200281 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282 if (cmd->opcode != opcode)
283 continue;
284
285 if (index >= 0 && cmd->index != index)
286 continue;
287
288 return cmd;
289 }
290
291 return NULL;
292}
293
Johan Hedberga664b5b2011-02-19 12:06:02 -0300294static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200295{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296 list_del(&cmd->list);
297 mgmt_pending_free(cmd);
298}
299
Szymon Janc4e51eae2011-02-25 19:05:48 +0100300static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200302 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300304 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
307 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100311 if (len != sizeof(*cp))
312 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
313
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317
Andre Guedes8c156c32011-07-07 10:30:36 -0300318 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
320 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200321 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200323 goto failed;
324 }
325
Szymon Janc4e51eae2011-02-25 19:05:48 +0100326 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
327 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
329 }
330
Szymon Janc4e51eae2011-02-25 19:05:48 +0100331 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300332 if (!cmd) {
333 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
Johan Hedberg72a734e2010-12-30 00:38:22 +0200337 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 queue_work(hdev->workqueue, &hdev->power_on);
339 else
340 queue_work(hdev->workqueue, &hdev->power_off);
341
Johan Hedberg366a0332011-02-19 12:05:55 -0300342 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
344failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300345 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300347 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348}
349
Szymon Janc4e51eae2011-02-25 19:05:48 +0100350static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
351 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200353 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300355 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 u8 scan;
357 int err;
358
359 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100363 if (len != sizeof(*cp))
364 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369
Andre Guedes8c156c32011-07-07 10:30:36 -0300370 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
372 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374 goto failed;
375 }
376
Szymon Janc4e51eae2011-02-25 19:05:48 +0100377 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
378 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
379 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200380 goto failed;
381 }
382
Johan Hedberg72a734e2010-12-30 00:38:22 +0200383 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200384 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100385 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 goto failed;
387 }
388
Szymon Janc4e51eae2011-02-25 19:05:48 +0100389 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300390 if (!cmd) {
391 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200392 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300393 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394
395 scan = SCAN_PAGE;
396
Johan Hedberg72a734e2010-12-30 00:38:22 +0200397 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398 scan |= SCAN_INQUIRY;
399
400 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
401 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300402 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
404failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300405 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200406 hci_dev_put(hdev);
407
408 return err;
409}
410
Szymon Janc4e51eae2011-02-25 19:05:48 +0100411static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
412 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200414 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300416 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200417 u8 scan;
418 int err;
419
420 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Janc4e51eae2011-02-25 19:05:48 +0100422 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100424 if (len != sizeof(*cp))
425 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
426
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
Andre Guedes8c156c32011-07-07 10:30:36 -0300431 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200432
433 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 goto failed;
436 }
437
Szymon Janc4e51eae2011-02-25 19:05:48 +0100438 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
439 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
440 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200441 goto failed;
442 }
443
Johan Hedberg72a734e2010-12-30 00:38:22 +0200444 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
447 }
448
Szymon Janc4e51eae2011-02-25 19:05:48 +0100449 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300450 if (!cmd) {
451 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300453 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454
Johan Hedberg72a734e2010-12-30 00:38:22 +0200455 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200456 scan = SCAN_PAGE;
457 else
458 scan = 0;
459
460 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
461 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300462 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463
464failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300465 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200466 hci_dev_put(hdev);
467
468 return err;
469}
470
Szymon Janc4e51eae2011-02-25 19:05:48 +0100471static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
472 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200473{
474 struct sk_buff *skb;
475 struct mgmt_hdr *hdr;
476
477 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
478 if (!skb)
479 return -ENOMEM;
480
481 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
482
483 hdr = (void *) skb_put(skb, sizeof(*hdr));
484 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100485 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200486 hdr->len = cpu_to_le16(data_len);
487
Szymon Janc4e51eae2011-02-25 19:05:48 +0100488 if (data)
489 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200490
491 hci_send_to_sock(NULL, skb, skip_sk);
492 kfree_skb(skb);
493
494 return 0;
495}
496
Johan Hedberg053f0212011-01-26 13:07:10 +0200497static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
498{
Johan Hedberga38528f2011-01-22 06:46:43 +0200499 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200500
Johan Hedberga38528f2011-01-22 06:46:43 +0200501 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200502
Szymon Janc4e51eae2011-02-25 19:05:48 +0100503 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200504}
505
Szymon Janc4e51eae2011-02-25 19:05:48 +0100506static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
507 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200508{
509 struct mgmt_mode *cp, ev;
510 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200511 int err;
512
513 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200514
Szymon Janc4e51eae2011-02-25 19:05:48 +0100515 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200516
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100517 if (len != sizeof(*cp))
518 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
Andre Guedes8c156c32011-07-07 10:30:36 -0300524 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200525
526 if (cp->val)
527 set_bit(HCI_PAIRABLE, &hdev->flags);
528 else
529 clear_bit(HCI_PAIRABLE, &hdev->flags);
530
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532 if (err < 0)
533 goto failed;
534
Johan Hedbergc542a062011-01-26 13:11:03 +0200535 ev.val = cp->val;
536
Szymon Janc4e51eae2011-02-25 19:05:48 +0100537 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200538
539failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300540 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200541 hci_dev_put(hdev);
542
543 return err;
544}
545
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546#define EIR_FLAGS 0x01 /* flags */
547#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
548#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
549#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
550#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
551#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
552#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
553#define EIR_NAME_SHORT 0x08 /* shortened local name */
554#define EIR_NAME_COMPLETE 0x09 /* complete local name */
555#define EIR_TX_POWER 0x0A /* transmit power level */
556#define EIR_DEVICE_ID 0x10 /* device ID */
557
558#define PNP_INFO_SVCLASS_ID 0x1200
559
560static u8 bluetooth_base_uuid[] = {
561 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
562 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563};
564
565static u16 get_uuid16(u8 *uuid128)
566{
567 u32 val;
568 int i;
569
570 for (i = 0; i < 12; i++) {
571 if (bluetooth_base_uuid[i] != uuid128[i])
572 return 0;
573 }
574
575 memcpy(&val, &uuid128[12], 4);
576
577 val = le32_to_cpu(val);
578 if (val > 0xffff)
579 return 0;
580
581 return (u16) val;
582}
583
584static void create_eir(struct hci_dev *hdev, u8 *data)
585{
586 u8 *ptr = data;
587 u16 eir_len = 0;
588 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
589 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200590 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591 size_t name_len;
592
593 name_len = strlen(hdev->dev_name);
594
595 if (name_len > 0) {
596 /* EIR Data type */
597 if (name_len > 48) {
598 name_len = 48;
599 ptr[1] = EIR_NAME_SHORT;
600 } else
601 ptr[1] = EIR_NAME_COMPLETE;
602
603 /* EIR Data length */
604 ptr[0] = name_len + 1;
605
606 memcpy(ptr + 2, hdev->dev_name, name_len);
607
608 eir_len += (name_len + 2);
609 ptr += (name_len + 2);
610 }
611
612 memset(uuid16_list, 0, sizeof(uuid16_list));
613
614 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200615 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300616 u16 uuid16;
617
618 uuid16 = get_uuid16(uuid->uuid);
619 if (uuid16 == 0)
620 return;
621
622 if (uuid16 < 0x1100)
623 continue;
624
625 if (uuid16 == PNP_INFO_SVCLASS_ID)
626 continue;
627
628 /* Stop if not enough space to put next UUID */
629 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
630 truncated = 1;
631 break;
632 }
633
634 /* Check for duplicates */
635 for (i = 0; uuid16_list[i] != 0; i++)
636 if (uuid16_list[i] == uuid16)
637 break;
638
639 if (uuid16_list[i] == 0) {
640 uuid16_list[i] = uuid16;
641 eir_len += sizeof(u16);
642 }
643 }
644
645 if (uuid16_list[0] != 0) {
646 u8 *length = ptr;
647
648 /* EIR Data type */
649 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
650
651 ptr += 2;
652 eir_len += 2;
653
654 for (i = 0; uuid16_list[i] != 0; i++) {
655 *ptr++ = (uuid16_list[i] & 0x00ff);
656 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
657 }
658
659 /* EIR Data length */
660 *length = (i * sizeof(u16)) + 1;
661 }
662}
663
664static int update_eir(struct hci_dev *hdev)
665{
666 struct hci_cp_write_eir cp;
667
668 if (!(hdev->features[6] & LMP_EXT_INQ))
669 return 0;
670
671 if (hdev->ssp_mode == 0)
672 return 0;
673
674 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
675 return 0;
676
677 memset(&cp, 0, sizeof(cp));
678
679 create_eir(hdev, cp.data);
680
681 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
682 return 0;
683
684 memcpy(hdev->eir, cp.data, sizeof(cp.data));
685
686 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
687}
688
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200689static u8 get_service_classes(struct hci_dev *hdev)
690{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300691 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200692 u8 val = 0;
693
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300694 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200695 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696
697 return val;
698}
699
700static int update_class(struct hci_dev *hdev)
701{
702 u8 cod[3];
703
704 BT_DBG("%s", hdev->name);
705
706 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
707 return 0;
708
709 cod[0] = hdev->minor_class;
710 cod[1] = hdev->major_class;
711 cod[2] = get_service_classes(hdev);
712
713 if (memcmp(cod, hdev->dev_class, 3) == 0)
714 return 0;
715
716 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
717}
718
Szymon Janc4e51eae2011-02-25 19:05:48 +0100719static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200720{
721 struct mgmt_cp_add_uuid *cp;
722 struct hci_dev *hdev;
723 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200724 int err;
725
726 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200727
Szymon Janc4e51eae2011-02-25 19:05:48 +0100728 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100730 if (len != sizeof(*cp))
731 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
732
Szymon Janc4e51eae2011-02-25 19:05:48 +0100733 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100735 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
Andre Guedes8c156c32011-07-07 10:30:36 -0300737 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200738
739 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
740 if (!uuid) {
741 err = -ENOMEM;
742 goto failed;
743 }
744
745 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200746 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200747
748 list_add(&uuid->list, &hdev->uuids);
749
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200750 err = update_class(hdev);
751 if (err < 0)
752 goto failed;
753
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300754 err = update_eir(hdev);
755 if (err < 0)
756 goto failed;
757
Szymon Janc4e51eae2011-02-25 19:05:48 +0100758 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200759
760failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300761 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200762 hci_dev_put(hdev);
763
764 return err;
765}
766
Szymon Janc4e51eae2011-02-25 19:05:48 +0100767static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768{
769 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100770 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771 struct hci_dev *hdev;
772 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 +0200773 int err, found;
774
775 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200776
Szymon Janc4e51eae2011-02-25 19:05:48 +0100777 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100779 if (len != sizeof(*cp))
780 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
781
Szymon Janc4e51eae2011-02-25 19:05:48 +0100782 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100784 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
Andre Guedes8c156c32011-07-07 10:30:36 -0300786 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200787
788 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
789 err = hci_uuids_clear(hdev);
790 goto unlock;
791 }
792
793 found = 0;
794
795 list_for_each_safe(p, n, &hdev->uuids) {
796 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
797
798 if (memcmp(match->uuid, cp->uuid, 16) != 0)
799 continue;
800
801 list_del(&match->list);
802 found++;
803 }
804
805 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100806 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200807 goto unlock;
808 }
809
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200810 err = update_class(hdev);
811 if (err < 0)
812 goto unlock;
813
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300814 err = update_eir(hdev);
815 if (err < 0)
816 goto unlock;
817
Szymon Janc4e51eae2011-02-25 19:05:48 +0100818 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200819
820unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300821 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200822 hci_dev_put(hdev);
823
824 return err;
825}
826
Szymon Janc4e51eae2011-02-25 19:05:48 +0100827static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
828 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200829{
830 struct hci_dev *hdev;
831 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200832 int err;
833
834 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200835
Szymon Janc4e51eae2011-02-25 19:05:48 +0100836 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200837
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100838 if (len != sizeof(*cp))
839 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
840
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100843 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
Andre Guedes8c156c32011-07-07 10:30:36 -0300845 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200846
847 hdev->major_class = cp->major;
848 hdev->minor_class = cp->minor;
849
850 err = update_class(hdev);
851
852 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100853 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200854
Andre Guedes8c156c32011-07-07 10:30:36 -0300855 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200856 hci_dev_put(hdev);
857
858 return err;
859}
860
Szymon Janc4e51eae2011-02-25 19:05:48 +0100861static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
862 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200863{
864 struct hci_dev *hdev;
865 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200866 int err;
867
868 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200869
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100870 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100871 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100872
Szymon Janc4e51eae2011-02-25 19:05:48 +0100873 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200874 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100875 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876
Andre Guedes8c156c32011-07-07 10:30:36 -0300877 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200880
881 if (cp->enable) {
882 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
883 err = 0;
884 } else {
885 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
886 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300887 if (err == 0)
888 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889 }
890
891 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100892 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
893 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300894 else
895 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
896
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897
Andre Guedes8c156c32011-07-07 10:30:36 -0300898 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200899 hci_dev_put(hdev);
900
901 return err;
902}
903
Szymon Janc4e51eae2011-02-25 19:05:48 +0100904static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200905{
906 struct hci_dev *hdev;
907 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100908 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300909 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200910
911 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100912
913 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300914 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100915
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200916 key_count = get_unaligned_le16(&cp->key_count);
917
918 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300919 if (expected_len != len) {
920 BT_ERR("load_keys: expected %u bytes, got %u bytes",
921 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300922 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200923 }
924
Szymon Janc4e51eae2011-02-25 19:05:48 +0100925 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200926 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928
Szymon Janc4e51eae2011-02-25 19:05:48 +0100929 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200930 key_count);
931
Andre Guedes8c156c32011-07-07 10:30:36 -0300932 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933
934 hci_link_keys_clear(hdev);
935
936 set_bit(HCI_LINK_KEYS, &hdev->flags);
937
938 if (cp->debug_keys)
939 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
940 else
941 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
942
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300943 for (i = 0; i < key_count; i++) {
944 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200945
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700946 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200947 key->pin_len);
948 }
949
Andre Guedes8c156c32011-07-07 10:30:36 -0300950 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200951 hci_dev_put(hdev);
952
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300953 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954}
955
Szymon Janc4e51eae2011-02-25 19:05:48 +0100956static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957{
958 struct hci_dev *hdev;
959 struct mgmt_cp_remove_key *cp;
960 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200961 int err;
962
963 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200964
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100965 if (len != sizeof(*cp))
966 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
967
Szymon Janc4e51eae2011-02-25 19:05:48 +0100968 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200969 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200971
Andre Guedes8c156c32011-07-07 10:30:36 -0300972 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200973
974 err = hci_remove_link_key(hdev, &cp->bdaddr);
975 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200977 goto unlock;
978 }
979
980 err = 0;
981
982 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
983 goto unlock;
984
985 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
986 if (conn) {
987 struct hci_cp_disconnect dc;
988
989 put_unaligned_le16(conn->handle, &dc.handle);
990 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400991 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200992 }
993
994unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300995 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200996 hci_dev_put(hdev);
997
998 return err;
999}
1000
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001002{
1003 struct hci_dev *hdev;
1004 struct mgmt_cp_disconnect *cp;
1005 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001006 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001007 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001008 int err;
1009
1010 BT_DBG("");
1011
1012 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001013
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001014 if (len != sizeof(*cp))
1015 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1016
Szymon Janc4e51eae2011-02-25 19:05:48 +01001017 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001018 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001019 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020
Andre Guedes8c156c32011-07-07 10:30:36 -03001021 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001022
1023 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025 goto failed;
1026 }
1027
Szymon Janc4e51eae2011-02-25 19:05:48 +01001028 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1029 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001030 goto failed;
1031 }
1032
1033 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001034 if (!conn)
1035 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1036
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001038 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001039 goto failed;
1040 }
1041
Szymon Janc4e51eae2011-02-25 19:05:48 +01001042 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001043 if (!cmd) {
1044 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001045 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001046 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001047
1048 put_unaligned_le16(conn->handle, &dc.handle);
1049 dc.reason = 0x13; /* Remote User Terminated Connection */
1050
1051 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1052 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001053 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001054
1055failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001056 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057 hci_dev_put(hdev);
1058
1059 return err;
1060}
1061
Szymon Janc8ce62842011-03-01 16:55:32 +01001062static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001063{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001064 struct mgmt_rp_get_connections *rp;
1065 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001066 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001067 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001068 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001069 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001070 int i, err;
1071
1072 BT_DBG("");
1073
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001075 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077
Andre Guedes8c156c32011-07-07 10:30:36 -03001078 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001079
1080 count = 0;
1081 list_for_each(p, &hdev->conn_hash.list) {
1082 count++;
1083 }
1084
Johan Hedberga38528f2011-01-22 06:46:43 +02001085 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1086 rp = kmalloc(rp_len, GFP_ATOMIC);
1087 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001088 err = -ENOMEM;
1089 goto unlock;
1090 }
1091
Johan Hedberg2784eb42011-01-21 13:56:35 +02001092 put_unaligned_le16(count, &rp->conn_count);
1093
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001095 list_for_each_entry(c, &hdev->conn_hash.list, list)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001096 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097
Szymon Janc4e51eae2011-02-25 19:05:48 +01001098 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099
1100unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001101 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001102 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001103 hci_dev_put(hdev);
1104 return err;
1105}
1106
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001107static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1108 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1109{
1110 struct pending_cmd *cmd;
1111 int err;
1112
1113 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1114 sizeof(*cp));
1115 if (!cmd)
1116 return -ENOMEM;
1117
1118 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1119 &cp->bdaddr);
1120 if (err < 0)
1121 mgmt_pending_remove(cmd);
1122
1123 return err;
1124}
1125
Szymon Janc4e51eae2011-02-25 19:05:48 +01001126static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1127 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001128{
1129 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001130 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001131 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001132 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001133 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001134 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001135 int err;
1136
1137 BT_DBG("");
1138
1139 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001140
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001141 if (len != sizeof(*cp))
1142 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1143
Szymon Janc4e51eae2011-02-25 19:05:48 +01001144 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001146 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001147
Andre Guedes8c156c32011-07-07 10:30:36 -03001148 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001149
1150 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152 goto failed;
1153 }
1154
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001155 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1156 if (!conn) {
1157 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1158 goto failed;
1159 }
1160
1161 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1162 bacpy(&ncp.bdaddr, &cp->bdaddr);
1163
1164 BT_ERR("PIN code is not 16 bytes long");
1165
1166 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1167 if (err >= 0)
1168 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1169 EINVAL);
1170
1171 goto failed;
1172 }
1173
Szymon Janc4e51eae2011-02-25 19:05:48 +01001174 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001175 if (!cmd) {
1176 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001178 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179
1180 bacpy(&reply.bdaddr, &cp->bdaddr);
1181 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001182 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001183
1184 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1185 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001186 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001187
1188failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001189 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001190 hci_dev_put(hdev);
1191
1192 return err;
1193}
1194
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1196 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001197{
1198 struct hci_dev *hdev;
1199 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200 int err;
1201
1202 BT_DBG("");
1203
1204 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001206 if (len != sizeof(*cp))
1207 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1208 EINVAL);
1209
Szymon Janc4e51eae2011-02-25 19:05:48 +01001210 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001211 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001212 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1213 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001214
Andre Guedes8c156c32011-07-07 10:30:36 -03001215 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001216
1217 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001218 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1219 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001220 goto failed;
1221 }
1222
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001223 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224
1225failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001226 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001227 hci_dev_put(hdev);
1228
1229 return err;
1230}
1231
Szymon Janc4e51eae2011-02-25 19:05:48 +01001232static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1233 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001234{
1235 struct hci_dev *hdev;
1236 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001237
1238 BT_DBG("");
1239
1240 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001241
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001242 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001243 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001244
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001246 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001247 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001248
Andre Guedes8c156c32011-07-07 10:30:36 -03001249 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001250
1251 hdev->io_capability = cp->io_capability;
1252
1253 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001254 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255
Andre Guedes8c156c32011-07-07 10:30:36 -03001256 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001257 hci_dev_put(hdev);
1258
Szymon Janc4e51eae2011-02-25 19:05:48 +01001259 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260}
1261
Johan Hedberge9a416b2011-02-19 12:05:56 -03001262static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1263{
1264 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001265 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001266
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001267 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001268 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1269 continue;
1270
1271 if (cmd->index != hdev->id)
1272 continue;
1273
1274 if (cmd->user_data != conn)
1275 continue;
1276
1277 return cmd;
1278 }
1279
1280 return NULL;
1281}
1282
1283static void pairing_complete(struct pending_cmd *cmd, u8 status)
1284{
1285 struct mgmt_rp_pair_device rp;
1286 struct hci_conn *conn = cmd->user_data;
1287
Johan Hedberge9a416b2011-02-19 12:05:56 -03001288 bacpy(&rp.bdaddr, &conn->dst);
1289 rp.status = status;
1290
Szymon Janc4e51eae2011-02-25 19:05:48 +01001291 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001292
1293 /* So we don't get further callbacks for this connection */
1294 conn->connect_cfm_cb = NULL;
1295 conn->security_cfm_cb = NULL;
1296 conn->disconn_cfm_cb = NULL;
1297
1298 hci_conn_put(conn);
1299
Johan Hedberga664b5b2011-02-19 12:06:02 -03001300 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001301}
1302
1303static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1304{
1305 struct pending_cmd *cmd;
1306
1307 BT_DBG("status %u", status);
1308
1309 cmd = find_pairing(conn);
1310 if (!cmd) {
1311 BT_DBG("Unable to find a pending command");
1312 return;
1313 }
1314
1315 pairing_complete(cmd, status);
1316}
1317
Szymon Janc4e51eae2011-02-25 19:05:48 +01001318static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001319{
1320 struct hci_dev *hdev;
1321 struct mgmt_cp_pair_device *cp;
1322 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001323 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324 u8 sec_level, auth_type;
1325 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001326 int err;
1327
1328 BT_DBG("");
1329
1330 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001332 if (len != sizeof(*cp))
1333 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1334
Szymon Janc4e51eae2011-02-25 19:05:48 +01001335 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338
Andre Guedes8c156c32011-07-07 10:30:36 -03001339 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001341 sec_level = BT_SECURITY_MEDIUM;
1342 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001344 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001346
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001347 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1348 if (entry)
1349 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1350 auth_type);
1351 else
1352 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1353 auth_type);
1354
Ville Tervo30e76272011-02-22 16:10:53 -03001355 if (IS_ERR(conn)) {
1356 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001357 goto unlock;
1358 }
1359
1360 if (conn->connect_cfm_cb) {
1361 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001362 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001363 goto unlock;
1364 }
1365
Szymon Janc4e51eae2011-02-25 19:05:48 +01001366 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001367 if (!cmd) {
1368 err = -ENOMEM;
1369 hci_conn_put(conn);
1370 goto unlock;
1371 }
1372
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001373 /* For LE, just connecting isn't a proof that the pairing finished */
1374 if (!entry)
1375 conn->connect_cfm_cb = pairing_complete_cb;
1376
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377 conn->security_cfm_cb = pairing_complete_cb;
1378 conn->disconn_cfm_cb = pairing_complete_cb;
1379 conn->io_capability = cp->io_cap;
1380 cmd->user_data = conn;
1381
1382 if (conn->state == BT_CONNECTED &&
1383 hci_conn_security(conn, sec_level, auth_type))
1384 pairing_complete(cmd, 0);
1385
1386 err = 0;
1387
1388unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001389 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001390 hci_dev_put(hdev);
1391
1392 return err;
1393}
1394
Szymon Janc4e51eae2011-02-25 19:05:48 +01001395static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1396 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001397{
1398 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001399 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001400 struct pending_cmd *cmd;
1401 struct hci_dev *hdev;
1402 int err;
1403
1404 BT_DBG("");
1405
Johan Hedberga5c29682011-02-19 12:05:57 -03001406 if (success) {
1407 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1408 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1409 } else {
1410 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1411 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1412 }
1413
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001414 if (len != sizeof(*cp))
1415 return cmd_status(sk, index, mgmt_op, EINVAL);
1416
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001418 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001420
Andre Guedes8c156c32011-07-07 10:30:36 -03001421 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001422
Johan Hedberga5c29682011-02-19 12:05:57 -03001423 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001425 goto failed;
1426 }
1427
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001429 if (!cmd) {
1430 err = -ENOMEM;
1431 goto failed;
1432 }
1433
1434 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001435 if (err < 0)
1436 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001437
1438failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001439 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001440 hci_dev_put(hdev);
1441
1442 return err;
1443}
1444
Johan Hedbergb312b1612011-03-16 14:29:37 +02001445static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1446 u16 len)
1447{
1448 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1449 struct hci_cp_write_local_name hci_cp;
1450 struct hci_dev *hdev;
1451 struct pending_cmd *cmd;
1452 int err;
1453
1454 BT_DBG("");
1455
1456 if (len != sizeof(*mgmt_cp))
1457 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1458
1459 hdev = hci_dev_get(index);
1460 if (!hdev)
1461 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1462
Andre Guedes8c156c32011-07-07 10:30:36 -03001463 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001464
1465 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1466 if (!cmd) {
1467 err = -ENOMEM;
1468 goto failed;
1469 }
1470
1471 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1472 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1473 &hci_cp);
1474 if (err < 0)
1475 mgmt_pending_remove(cmd);
1476
1477failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001478 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001479 hci_dev_put(hdev);
1480
1481 return err;
1482}
1483
Szymon Jancc35938b2011-03-22 13:12:21 +01001484static int read_local_oob_data(struct sock *sk, u16 index)
1485{
1486 struct hci_dev *hdev;
1487 struct pending_cmd *cmd;
1488 int err;
1489
1490 BT_DBG("hci%u", index);
1491
1492 hdev = hci_dev_get(index);
1493 if (!hdev)
1494 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1495 ENODEV);
1496
Andre Guedes8c156c32011-07-07 10:30:36 -03001497 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001498
1499 if (!test_bit(HCI_UP, &hdev->flags)) {
1500 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1501 ENETDOWN);
1502 goto unlock;
1503 }
1504
1505 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1506 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1507 EOPNOTSUPP);
1508 goto unlock;
1509 }
1510
1511 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1512 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1513 goto unlock;
1514 }
1515
1516 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1517 if (!cmd) {
1518 err = -ENOMEM;
1519 goto unlock;
1520 }
1521
1522 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1523 if (err < 0)
1524 mgmt_pending_remove(cmd);
1525
1526unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001527 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001528 hci_dev_put(hdev);
1529
1530 return err;
1531}
1532
Szymon Janc2763eda2011-03-22 13:12:22 +01001533static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1534 u16 len)
1535{
1536 struct hci_dev *hdev;
1537 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1538 int err;
1539
1540 BT_DBG("hci%u ", index);
1541
1542 if (len != sizeof(*cp))
1543 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1544 EINVAL);
1545
1546 hdev = hci_dev_get(index);
1547 if (!hdev)
1548 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1549 ENODEV);
1550
Andre Guedes8c156c32011-07-07 10:30:36 -03001551 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001552
1553 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1554 cp->randomizer);
1555 if (err < 0)
1556 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1557 else
1558 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1559 0);
1560
Andre Guedes8c156c32011-07-07 10:30:36 -03001561 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001562 hci_dev_put(hdev);
1563
1564 return err;
1565}
1566
1567static int remove_remote_oob_data(struct sock *sk, u16 index,
1568 unsigned char *data, u16 len)
1569{
1570 struct hci_dev *hdev;
1571 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1572 int err;
1573
1574 BT_DBG("hci%u ", index);
1575
1576 if (len != sizeof(*cp))
1577 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1578 EINVAL);
1579
1580 hdev = hci_dev_get(index);
1581 if (!hdev)
1582 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1583 ENODEV);
1584
Andre Guedes8c156c32011-07-07 10:30:36 -03001585 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001586
1587 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1588 if (err < 0)
1589 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1590 -err);
1591 else
1592 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1593 NULL, 0);
1594
Andre Guedes8c156c32011-07-07 10:30:36 -03001595 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001596 hci_dev_put(hdev);
1597
1598 return err;
1599}
1600
Johan Hedberg14a53662011-04-27 10:29:56 -04001601static int start_discovery(struct sock *sk, u16 index)
1602{
Johan Hedberg14a53662011-04-27 10:29:56 -04001603 struct pending_cmd *cmd;
1604 struct hci_dev *hdev;
1605 int err;
1606
1607 BT_DBG("hci%u", index);
1608
1609 hdev = hci_dev_get(index);
1610 if (!hdev)
1611 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1612
1613 hci_dev_lock_bh(hdev);
1614
1615 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1616 if (!cmd) {
1617 err = -ENOMEM;
1618 goto failed;
1619 }
1620
Andre Guedes2519a1f2011-11-07 11:45:24 -03001621 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001622 if (err < 0)
1623 mgmt_pending_remove(cmd);
1624
1625failed:
1626 hci_dev_unlock_bh(hdev);
1627 hci_dev_put(hdev);
1628
1629 return err;
1630}
1631
1632static int stop_discovery(struct sock *sk, u16 index)
1633{
1634 struct hci_dev *hdev;
1635 struct pending_cmd *cmd;
1636 int err;
1637
1638 BT_DBG("hci%u", index);
1639
1640 hdev = hci_dev_get(index);
1641 if (!hdev)
1642 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1643
1644 hci_dev_lock_bh(hdev);
1645
1646 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1647 if (!cmd) {
1648 err = -ENOMEM;
1649 goto failed;
1650 }
1651
1652 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1653 if (err < 0)
1654 mgmt_pending_remove(cmd);
1655
1656failed:
1657 hci_dev_unlock_bh(hdev);
1658 hci_dev_put(hdev);
1659
1660 return err;
1661}
1662
Antti Julku7fbec222011-06-15 12:01:15 +03001663static int block_device(struct sock *sk, u16 index, unsigned char *data,
1664 u16 len)
1665{
1666 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001667 struct pending_cmd *cmd;
1668 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001669 int err;
1670
1671 BT_DBG("hci%u", index);
1672
Antti Julku7fbec222011-06-15 12:01:15 +03001673 if (len != sizeof(*cp))
1674 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1675 EINVAL);
1676
1677 hdev = hci_dev_get(index);
1678 if (!hdev)
1679 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1680 ENODEV);
1681
Antti Julku5e762442011-08-25 16:48:02 +03001682 hci_dev_lock_bh(hdev);
1683
1684 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1685 if (!cmd) {
1686 err = -ENOMEM;
1687 goto failed;
1688 }
1689
Antti Julku7fbec222011-06-15 12:01:15 +03001690 err = hci_blacklist_add(hdev, &cp->bdaddr);
1691
1692 if (err < 0)
1693 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1694 else
1695 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1696 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001697
1698 mgmt_pending_remove(cmd);
1699
1700failed:
1701 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001702 hci_dev_put(hdev);
1703
1704 return err;
1705}
1706
1707static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1708 u16 len)
1709{
1710 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001711 struct pending_cmd *cmd;
1712 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001713 int err;
1714
1715 BT_DBG("hci%u", index);
1716
Antti Julku7fbec222011-06-15 12:01:15 +03001717 if (len != sizeof(*cp))
1718 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1719 EINVAL);
1720
1721 hdev = hci_dev_get(index);
1722 if (!hdev)
1723 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1724 ENODEV);
1725
Antti Julku5e762442011-08-25 16:48:02 +03001726 hci_dev_lock_bh(hdev);
1727
1728 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1729 if (!cmd) {
1730 err = -ENOMEM;
1731 goto failed;
1732 }
1733
Antti Julku7fbec222011-06-15 12:01:15 +03001734 err = hci_blacklist_del(hdev, &cp->bdaddr);
1735
1736 if (err < 0)
1737 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1738 else
1739 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1740 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001741
1742 mgmt_pending_remove(cmd);
1743
1744failed:
1745 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001746 hci_dev_put(hdev);
1747
1748 return err;
1749}
1750
Antti Julkuf6422ec2011-06-22 13:11:56 +03001751static int set_fast_connectable(struct sock *sk, u16 index,
1752 unsigned char *data, u16 len)
1753{
1754 struct hci_dev *hdev;
1755 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1756 struct hci_cp_write_page_scan_activity acp;
1757 u8 type;
1758 int err;
1759
1760 BT_DBG("hci%u", index);
1761
1762 if (len != sizeof(*cp))
1763 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1764 EINVAL);
1765
1766 hdev = hci_dev_get(index);
1767 if (!hdev)
1768 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1769 ENODEV);
1770
1771 hci_dev_lock(hdev);
1772
1773 if (cp->enable) {
1774 type = PAGE_SCAN_TYPE_INTERLACED;
1775 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1776 } else {
1777 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1778 acp.interval = 0x0800; /* default 1.28 sec page scan */
1779 }
1780
1781 acp.window = 0x0012; /* default 11.25 msec page scan window */
1782
1783 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1784 sizeof(acp), &acp);
1785 if (err < 0) {
1786 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1787 -err);
1788 goto done;
1789 }
1790
1791 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1792 if (err < 0) {
1793 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1794 -err);
1795 goto done;
1796 }
1797
1798 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1799 NULL, 0);
1800done:
1801 hci_dev_unlock(hdev);
1802 hci_dev_put(hdev);
1803
1804 return err;
1805}
1806
Johan Hedberg03811012010-12-08 00:21:06 +02001807int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1808{
1809 unsigned char *buf;
1810 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001811 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001812 int err;
1813
1814 BT_DBG("got %zu bytes", msglen);
1815
1816 if (msglen < sizeof(*hdr))
1817 return -EINVAL;
1818
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001819 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001820 if (!buf)
1821 return -ENOMEM;
1822
1823 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1824 err = -EFAULT;
1825 goto done;
1826 }
1827
1828 hdr = (struct mgmt_hdr *) buf;
1829 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001830 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001831 len = get_unaligned_le16(&hdr->len);
1832
1833 if (len != msglen - sizeof(*hdr)) {
1834 err = -EINVAL;
1835 goto done;
1836 }
1837
1838 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001839 case MGMT_OP_READ_VERSION:
1840 err = read_version(sk);
1841 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001842 case MGMT_OP_READ_INDEX_LIST:
1843 err = read_index_list(sk);
1844 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001845 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001847 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001848 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001850 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001851 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001852 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001853 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001854 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001855 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001856 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001857 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001858 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001859 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001860 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001861 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001862 break;
1863 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001865 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001866 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001867 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001868 break;
1869 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001870 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001871 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001872 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001874 break;
1875 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001877 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001878 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001879 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001880 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001881 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001882 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001883 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001884 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001886 break;
1887 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001890 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001892 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001896 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001897 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001898 break;
1899 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001900 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001901 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001902 case MGMT_OP_SET_LOCAL_NAME:
1903 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1904 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001905 case MGMT_OP_READ_LOCAL_OOB_DATA:
1906 err = read_local_oob_data(sk, index);
1907 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001908 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1909 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1910 break;
1911 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1912 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1913 len);
1914 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001915 case MGMT_OP_START_DISCOVERY:
1916 err = start_discovery(sk, index);
1917 break;
1918 case MGMT_OP_STOP_DISCOVERY:
1919 err = stop_discovery(sk, index);
1920 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001921 case MGMT_OP_BLOCK_DEVICE:
1922 err = block_device(sk, index, buf + sizeof(*hdr), len);
1923 break;
1924 case MGMT_OP_UNBLOCK_DEVICE:
1925 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1926 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001927 case MGMT_OP_SET_FAST_CONNECTABLE:
1928 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1929 len);
1930 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001931 default:
1932 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001933 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001934 break;
1935 }
1936
Johan Hedberge41d8b42010-12-13 21:07:03 +02001937 if (err < 0)
1938 goto done;
1939
Johan Hedberg03811012010-12-08 00:21:06 +02001940 err = msglen;
1941
1942done:
1943 kfree(buf);
1944 return err;
1945}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001946
Johan Hedbergb24752f2011-11-03 14:40:33 +02001947static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1948{
1949 u8 *status = data;
1950
1951 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1952 mgmt_pending_remove(cmd);
1953}
1954
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001955int mgmt_index_added(u16 index)
1956{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001957 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001958}
1959
1960int mgmt_index_removed(u16 index)
1961{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001962 u8 status = ENODEV;
1963
1964 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1965
Szymon Janc4e51eae2011-02-25 19:05:48 +01001966 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001967}
1968
Johan Hedberg73f22f62010-12-29 16:00:25 +02001969struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001970 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001971 struct sock *sk;
1972};
1973
Johan Hedberg72a734e2010-12-30 00:38:22 +02001974static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001975{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001976 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001977 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978
Johan Hedberg72a734e2010-12-30 00:38:22 +02001979 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001980 return;
1981
Johan Hedberg053f0212011-01-26 13:07:10 +02001982 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001983
1984 list_del(&cmd->list);
1985
1986 if (match->sk == NULL) {
1987 match->sk = cmd->sk;
1988 sock_hold(match->sk);
1989 }
1990
1991 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001992}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001993
1994int mgmt_powered(u16 index, u8 powered)
1995{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001996 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001997 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001998 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001999
Johan Hedberg72a734e2010-12-30 00:38:22 +02002000 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002001
Johan Hedbergb24752f2011-11-03 14:40:33 +02002002 if (!powered) {
2003 u8 status = ENETDOWN;
2004 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2005 }
2006
Johan Hedberg72a734e2010-12-30 00:38:22 +02002007 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002008
Szymon Janc4e51eae2011-02-25 19:05:48 +01002009 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002010
2011 if (match.sk)
2012 sock_put(match.sk);
2013
2014 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002015}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002016
Johan Hedberg73f22f62010-12-29 16:00:25 +02002017int mgmt_discoverable(u16 index, u8 discoverable)
2018{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002019 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002020 struct cmd_lookup match = { discoverable, NULL };
2021 int ret;
2022
Szymon Jancb8534e02011-03-01 16:55:34 +01002023 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024
Johan Hedberg72a734e2010-12-30 00:38:22 +02002025 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002026
Szymon Janc4e51eae2011-02-25 19:05:48 +01002027 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2028 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002029
2030 if (match.sk)
2031 sock_put(match.sk);
2032
2033 return ret;
2034}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002035
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002036int mgmt_connectable(u16 index, u8 connectable)
2037{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002038 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002039 struct cmd_lookup match = { connectable, NULL };
2040 int ret;
2041
Johan Hedberg72a734e2010-12-30 00:38:22 +02002042 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002043
Johan Hedberg72a734e2010-12-30 00:38:22 +02002044 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002045
Szymon Janc4e51eae2011-02-25 19:05:48 +01002046 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002047
2048 if (match.sk)
2049 sock_put(match.sk);
2050
2051 return ret;
2052}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002053
Johan Hedberg4df378a2011-04-28 11:29:03 -07002054int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002055{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002056 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002057
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002058 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002059
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002060 ev.store_hint = persistent;
2061 bacpy(&ev.key.bdaddr, &key->bdaddr);
2062 ev.key.type = key->type;
2063 memcpy(ev.key.val, key->val, 16);
2064 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002065
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002066 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002067}
Johan Hedbergf7520542011-01-20 12:34:39 +02002068
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002069int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002070{
2071 struct mgmt_ev_connected ev;
2072
Johan Hedbergf7520542011-01-20 12:34:39 +02002073 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002074 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002075
Szymon Janc4e51eae2011-02-25 19:05:48 +01002076 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002077}
2078
Johan Hedberg8962ee72011-01-20 12:40:27 +02002079static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2080{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002081 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002082 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002083 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084
Johan Hedberga38528f2011-01-22 06:46:43 +02002085 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002086
Szymon Janc4e51eae2011-02-25 19:05:48 +01002087 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002088
2089 *sk = cmd->sk;
2090 sock_hold(*sk);
2091
Johan Hedberga664b5b2011-02-19 12:06:02 -03002092 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002093}
2094
Johan Hedbergf7520542011-01-20 12:34:39 +02002095int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2096{
2097 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002098 struct sock *sk = NULL;
2099 int err;
2100
2101 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002102
Johan Hedbergf7520542011-01-20 12:34:39 +02002103 bacpy(&ev.bdaddr, bdaddr);
2104
Szymon Janc4e51eae2011-02-25 19:05:48 +01002105 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002106
2107 if (sk)
2108 sock_put(sk);
2109
2110 return err;
2111}
2112
2113int mgmt_disconnect_failed(u16 index)
2114{
2115 struct pending_cmd *cmd;
2116 int err;
2117
2118 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2119 if (!cmd)
2120 return -ENOENT;
2121
Szymon Janc4e51eae2011-02-25 19:05:48 +01002122 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123
Johan Hedberga664b5b2011-02-19 12:06:02 -03002124 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002125
2126 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002127}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002128
2129int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2130{
2131 struct mgmt_ev_connect_failed ev;
2132
Johan Hedberg17d5c042011-01-22 06:09:08 +02002133 bacpy(&ev.bdaddr, bdaddr);
2134 ev.status = status;
2135
Szymon Janc4e51eae2011-02-25 19:05:48 +01002136 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002137}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002139int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140{
2141 struct mgmt_ev_pin_code_request ev;
2142
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002144 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2147 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148}
2149
2150int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2151{
2152 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002153 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002154 int err;
2155
2156 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2157 if (!cmd)
2158 return -ENOENT;
2159
Johan Hedbergac56fb12011-02-19 12:05:59 -03002160 bacpy(&rp.bdaddr, bdaddr);
2161 rp.status = status;
2162
Szymon Janc4e51eae2011-02-25 19:05:48 +01002163 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2164 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002165
Johan Hedberga664b5b2011-02-19 12:06:02 -03002166 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002167
2168 return err;
2169}
2170
2171int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2172{
2173 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002174 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175 int err;
2176
2177 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2178 if (!cmd)
2179 return -ENOENT;
2180
Johan Hedbergac56fb12011-02-19 12:05:59 -03002181 bacpy(&rp.bdaddr, bdaddr);
2182 rp.status = status;
2183
Szymon Janc4e51eae2011-02-25 19:05:48 +01002184 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2185 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186
Johan Hedberga664b5b2011-02-19 12:06:02 -03002187 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188
2189 return err;
2190}
Johan Hedberga5c29682011-02-19 12:05:57 -03002191
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002192int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2193 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002194{
2195 struct mgmt_ev_user_confirm_request ev;
2196
2197 BT_DBG("hci%u", index);
2198
Johan Hedberga5c29682011-02-19 12:05:57 -03002199 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002200 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002201 put_unaligned_le32(value, &ev.value);
2202
Szymon Janc4e51eae2011-02-25 19:05:48 +01002203 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2204 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002205}
2206
2207static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2208 u8 opcode)
2209{
2210 struct pending_cmd *cmd;
2211 struct mgmt_rp_user_confirm_reply rp;
2212 int err;
2213
2214 cmd = mgmt_pending_find(opcode, index);
2215 if (!cmd)
2216 return -ENOENT;
2217
Johan Hedberga5c29682011-02-19 12:05:57 -03002218 bacpy(&rp.bdaddr, bdaddr);
2219 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002220 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002221
Johan Hedberga664b5b2011-02-19 12:06:02 -03002222 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002223
2224 return err;
2225}
2226
2227int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2228{
2229 return confirm_reply_complete(index, bdaddr, status,
2230 MGMT_OP_USER_CONFIRM_REPLY);
2231}
2232
Szymon Jancb8534e02011-03-01 16:55:34 +01002233int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002234{
2235 return confirm_reply_complete(index, bdaddr, status,
2236 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2237}
Johan Hedberg2a611692011-02-19 12:06:00 -03002238
2239int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2240{
2241 struct mgmt_ev_auth_failed ev;
2242
Johan Hedberg2a611692011-02-19 12:06:00 -03002243 bacpy(&ev.bdaddr, bdaddr);
2244 ev.status = status;
2245
Szymon Janc4e51eae2011-02-25 19:05:48 +01002246 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002247}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002248
2249int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2250{
2251 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002252 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002253 struct mgmt_cp_set_local_name ev;
2254 int err;
2255
2256 memset(&ev, 0, sizeof(ev));
2257 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2258
2259 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2260 if (!cmd)
2261 goto send_event;
2262
2263 if (status) {
2264 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2265 goto failed;
2266 }
2267
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002268 hdev = hci_dev_get(index);
2269 if (hdev) {
2270 hci_dev_lock_bh(hdev);
2271 update_eir(hdev);
2272 hci_dev_unlock_bh(hdev);
2273 hci_dev_put(hdev);
2274 }
2275
Johan Hedbergb312b1612011-03-16 14:29:37 +02002276 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2277 sizeof(ev));
2278 if (err < 0)
2279 goto failed;
2280
2281send_event:
2282 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2283 cmd ? cmd->sk : NULL);
2284
2285failed:
2286 if (cmd)
2287 mgmt_pending_remove(cmd);
2288 return err;
2289}
Szymon Jancc35938b2011-03-22 13:12:21 +01002290
2291int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2292 u8 status)
2293{
2294 struct pending_cmd *cmd;
2295 int err;
2296
2297 BT_DBG("hci%u status %u", index, status);
2298
2299 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2300 if (!cmd)
2301 return -ENOENT;
2302
2303 if (status) {
2304 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2305 EIO);
2306 } else {
2307 struct mgmt_rp_read_local_oob_data rp;
2308
2309 memcpy(rp.hash, hash, sizeof(rp.hash));
2310 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2311
2312 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2313 &rp, sizeof(rp));
2314 }
2315
2316 mgmt_pending_remove(cmd);
2317
2318 return err;
2319}
Johan Hedberge17acd42011-03-30 23:57:16 +03002320
2321int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2322 u8 *eir)
2323{
2324 struct mgmt_ev_device_found ev;
2325
2326 memset(&ev, 0, sizeof(ev));
2327
2328 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002329 ev.rssi = rssi;
2330
2331 if (eir)
2332 memcpy(ev.eir, eir, sizeof(ev.eir));
2333
Andre Guedesf8523592011-09-09 18:56:26 -03002334 if (dev_class)
2335 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2336
Johan Hedberge17acd42011-03-30 23:57:16 +03002337 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2338}
Johan Hedberga88a9652011-03-30 13:18:12 +03002339
2340int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2341{
2342 struct mgmt_ev_remote_name ev;
2343
2344 memset(&ev, 0, sizeof(ev));
2345
2346 bacpy(&ev.bdaddr, bdaddr);
2347 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2348
2349 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2350}
Johan Hedberg314b2382011-04-27 10:29:57 -04002351
Johan Hedberg164a6e72011-11-01 17:06:44 +02002352int mgmt_inquiry_failed(u16 index, u8 status)
2353{
2354 struct pending_cmd *cmd;
2355 int err;
2356
2357 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2358 if (!cmd)
2359 return -ENOENT;
2360
2361 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2362 mgmt_pending_remove(cmd);
2363
2364 return err;
2365}
2366
Johan Hedberg314b2382011-04-27 10:29:57 -04002367int mgmt_discovering(u16 index, u8 discovering)
2368{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002369 struct pending_cmd *cmd;
2370
2371 if (discovering)
2372 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2373 else
2374 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2375
2376 if (cmd != NULL) {
2377 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2378 mgmt_pending_remove(cmd);
2379 }
2380
Johan Hedberg314b2382011-04-27 10:29:57 -04002381 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2382 sizeof(discovering), NULL);
2383}
Antti Julku5e762442011-08-25 16:48:02 +03002384
2385int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2386{
2387 struct pending_cmd *cmd;
2388 struct mgmt_ev_device_blocked ev;
2389
2390 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2391
2392 bacpy(&ev.bdaddr, bdaddr);
2393
2394 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2395 cmd ? cmd->sk : NULL);
2396}
2397
2398int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2399{
2400 struct pending_cmd *cmd;
2401 struct mgmt_ev_device_unblocked ev;
2402
2403 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2404
2405 bacpy(&ev.bdaddr, bdaddr);
2406
2407 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2408 cmd ? cmd->sk : NULL);
2409}