blob: 38220a2dc31e9f3e45daf98f6dae303d9d026369 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
Johannes Bergb5ad8b72011-06-01 08:54:45 +020044static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030051 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020052
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030069 err = sock_queue_rcv_skb(sk, skb);
70 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020074}
75
Szymon Janc4e51eae2011-02-25 19:05:48 +010076static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
77 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020078{
79 struct sk_buff *skb;
80 struct mgmt_hdr *hdr;
81 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030082 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020083
84 BT_DBG("sock %p", sk);
85
Johan Hedberga38528f2011-01-22 06:46:43 +020086 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020087 if (!skb)
88 return -ENOMEM;
89
90 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020091
Johan Hedberg02d98122010-12-13 21:07:04 +020092 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010093 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020094 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020095
Johan Hedberga38528f2011-01-22 06:46:43 +020096 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
97 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010098
99 if (rp)
100 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300102 err = sock_queue_rcv_skb(sk, skb);
103 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200104 kfree_skb(skb);
105
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300106 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200107}
108
Johan Hedberga38528f2011-01-22 06:46:43 +0200109static int read_version(struct sock *sk)
110{
111 struct mgmt_rp_read_version rp;
112
113 BT_DBG("sock %p", sk);
114
115 rp.version = MGMT_VERSION;
116 put_unaligned_le16(MGMT_REVISION, &rp.revision);
117
Szymon Janc4e51eae2011-02-25 19:05:48 +0100118 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
119 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200120}
121
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200122static int read_index_list(struct sock *sk)
123{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 struct mgmt_rp_read_index_list *rp;
125 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200126 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200127 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200128 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130
131 BT_DBG("sock %p", sk);
132
133 read_lock(&hci_dev_list_lock);
134
135 count = 0;
136 list_for_each(p, &hci_dev_list) {
137 count++;
138 }
139
Johan Hedberga38528f2011-01-22 06:46:43 +0200140 rp_len = sizeof(*rp) + (2 * count);
141 rp = kmalloc(rp_len, GFP_ATOMIC);
142 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100143 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200144 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147 put_unaligned_le16(count, &rp->num_controllers);
148
149 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200150 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200151 hci_del_off_timer(d);
152
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200153 set_bit(HCI_MGMT, &d->flags);
154
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200155 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
267 if (cmd->opcode != opcode)
268 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{
1603 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1604 struct hci_cp_inquiry cp;
1605 struct pending_cmd *cmd;
1606 struct hci_dev *hdev;
1607 int err;
1608
1609 BT_DBG("hci%u", index);
1610
1611 hdev = hci_dev_get(index);
1612 if (!hdev)
1613 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1614
1615 hci_dev_lock_bh(hdev);
1616
1617 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1618 if (!cmd) {
1619 err = -ENOMEM;
1620 goto failed;
1621 }
1622
1623 memset(&cp, 0, sizeof(cp));
1624 memcpy(&cp.lap, lap, 3);
1625 cp.length = 0x08;
1626 cp.num_rsp = 0x00;
1627
1628 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1629 if (err < 0)
1630 mgmt_pending_remove(cmd);
1631
1632failed:
1633 hci_dev_unlock_bh(hdev);
1634 hci_dev_put(hdev);
1635
1636 return err;
1637}
1638
1639static int stop_discovery(struct sock *sk, u16 index)
1640{
1641 struct hci_dev *hdev;
1642 struct pending_cmd *cmd;
1643 int err;
1644
1645 BT_DBG("hci%u", index);
1646
1647 hdev = hci_dev_get(index);
1648 if (!hdev)
1649 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1650
1651 hci_dev_lock_bh(hdev);
1652
1653 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1654 if (!cmd) {
1655 err = -ENOMEM;
1656 goto failed;
1657 }
1658
1659 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1660 if (err < 0)
1661 mgmt_pending_remove(cmd);
1662
1663failed:
1664 hci_dev_unlock_bh(hdev);
1665 hci_dev_put(hdev);
1666
1667 return err;
1668}
1669
Antti Julku7fbec222011-06-15 12:01:15 +03001670static int block_device(struct sock *sk, u16 index, unsigned char *data,
1671 u16 len)
1672{
1673 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001674 struct pending_cmd *cmd;
1675 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001676 int err;
1677
1678 BT_DBG("hci%u", index);
1679
Antti Julku7fbec222011-06-15 12:01:15 +03001680 if (len != sizeof(*cp))
1681 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1682 EINVAL);
1683
1684 hdev = hci_dev_get(index);
1685 if (!hdev)
1686 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1687 ENODEV);
1688
Antti Julku5e762442011-08-25 16:48:02 +03001689 hci_dev_lock_bh(hdev);
1690
1691 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1692 if (!cmd) {
1693 err = -ENOMEM;
1694 goto failed;
1695 }
1696
Antti Julku7fbec222011-06-15 12:01:15 +03001697 err = hci_blacklist_add(hdev, &cp->bdaddr);
1698
1699 if (err < 0)
1700 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1701 else
1702 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1703 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001704
1705 mgmt_pending_remove(cmd);
1706
1707failed:
1708 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001709 hci_dev_put(hdev);
1710
1711 return err;
1712}
1713
1714static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1715 u16 len)
1716{
1717 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001718 struct pending_cmd *cmd;
1719 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001720 int err;
1721
1722 BT_DBG("hci%u", index);
1723
Antti Julku7fbec222011-06-15 12:01:15 +03001724 if (len != sizeof(*cp))
1725 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1726 EINVAL);
1727
1728 hdev = hci_dev_get(index);
1729 if (!hdev)
1730 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1731 ENODEV);
1732
Antti Julku5e762442011-08-25 16:48:02 +03001733 hci_dev_lock_bh(hdev);
1734
1735 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1736 if (!cmd) {
1737 err = -ENOMEM;
1738 goto failed;
1739 }
1740
Antti Julku7fbec222011-06-15 12:01:15 +03001741 err = hci_blacklist_del(hdev, &cp->bdaddr);
1742
1743 if (err < 0)
1744 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1745 else
1746 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1747 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001748
1749 mgmt_pending_remove(cmd);
1750
1751failed:
1752 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001753 hci_dev_put(hdev);
1754
1755 return err;
1756}
1757
Antti Julkuf6422ec2011-06-22 13:11:56 +03001758static int set_fast_connectable(struct sock *sk, u16 index,
1759 unsigned char *data, u16 len)
1760{
1761 struct hci_dev *hdev;
1762 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1763 struct hci_cp_write_page_scan_activity acp;
1764 u8 type;
1765 int err;
1766
1767 BT_DBG("hci%u", index);
1768
1769 if (len != sizeof(*cp))
1770 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1771 EINVAL);
1772
1773 hdev = hci_dev_get(index);
1774 if (!hdev)
1775 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1776 ENODEV);
1777
1778 hci_dev_lock(hdev);
1779
1780 if (cp->enable) {
1781 type = PAGE_SCAN_TYPE_INTERLACED;
1782 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1783 } else {
1784 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1785 acp.interval = 0x0800; /* default 1.28 sec page scan */
1786 }
1787
1788 acp.window = 0x0012; /* default 11.25 msec page scan window */
1789
1790 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1791 sizeof(acp), &acp);
1792 if (err < 0) {
1793 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1794 -err);
1795 goto done;
1796 }
1797
1798 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1799 if (err < 0) {
1800 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1801 -err);
1802 goto done;
1803 }
1804
1805 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1806 NULL, 0);
1807done:
1808 hci_dev_unlock(hdev);
1809 hci_dev_put(hdev);
1810
1811 return err;
1812}
1813
Johan Hedberg03811012010-12-08 00:21:06 +02001814int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1815{
1816 unsigned char *buf;
1817 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001818 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001819 int err;
1820
1821 BT_DBG("got %zu bytes", msglen);
1822
1823 if (msglen < sizeof(*hdr))
1824 return -EINVAL;
1825
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001826 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001827 if (!buf)
1828 return -ENOMEM;
1829
1830 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1831 err = -EFAULT;
1832 goto done;
1833 }
1834
1835 hdr = (struct mgmt_hdr *) buf;
1836 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001837 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001838 len = get_unaligned_le16(&hdr->len);
1839
1840 if (len != msglen - sizeof(*hdr)) {
1841 err = -EINVAL;
1842 goto done;
1843 }
1844
1845 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001846 case MGMT_OP_READ_VERSION:
1847 err = read_version(sk);
1848 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001849 case MGMT_OP_READ_INDEX_LIST:
1850 err = read_index_list(sk);
1851 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001852 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001853 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001854 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001855 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001856 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001857 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001858 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001859 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001860 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001861 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001863 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001864 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001866 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001867 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001869 break;
1870 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001872 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001873 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001875 break;
1876 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001878 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881 break;
1882 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001884 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001885 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001887 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001888 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001889 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001890 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001891 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001893 break;
1894 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001896 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001897 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001899 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001903 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001905 break;
1906 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001908 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001909 case MGMT_OP_SET_LOCAL_NAME:
1910 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1911 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001912 case MGMT_OP_READ_LOCAL_OOB_DATA:
1913 err = read_local_oob_data(sk, index);
1914 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001915 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1916 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1917 break;
1918 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1919 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1920 len);
1921 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001922 case MGMT_OP_START_DISCOVERY:
1923 err = start_discovery(sk, index);
1924 break;
1925 case MGMT_OP_STOP_DISCOVERY:
1926 err = stop_discovery(sk, index);
1927 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001928 case MGMT_OP_BLOCK_DEVICE:
1929 err = block_device(sk, index, buf + sizeof(*hdr), len);
1930 break;
1931 case MGMT_OP_UNBLOCK_DEVICE:
1932 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1933 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001934 case MGMT_OP_SET_FAST_CONNECTABLE:
1935 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1936 len);
1937 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001938 default:
1939 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001940 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001941 break;
1942 }
1943
Johan Hedberge41d8b42010-12-13 21:07:03 +02001944 if (err < 0)
1945 goto done;
1946
Johan Hedberg03811012010-12-08 00:21:06 +02001947 err = msglen;
1948
1949done:
1950 kfree(buf);
1951 return err;
1952}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001953
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001954int mgmt_index_added(u16 index)
1955{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001956 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001957}
1958
1959int mgmt_index_removed(u16 index)
1960{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001961 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001962}
1963
Johan Hedberg73f22f62010-12-29 16:00:25 +02001964struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001965 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001966 struct sock *sk;
1967};
1968
Johan Hedberg72a734e2010-12-30 00:38:22 +02001969static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001970{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001971 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001972 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001973
Johan Hedberg72a734e2010-12-30 00:38:22 +02001974 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001975 return;
1976
Johan Hedberg053f0212011-01-26 13:07:10 +02001977 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978
1979 list_del(&cmd->list);
1980
1981 if (match->sk == NULL) {
1982 match->sk = cmd->sk;
1983 sock_hold(match->sk);
1984 }
1985
1986 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001987}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001988
1989int mgmt_powered(u16 index, u8 powered)
1990{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001991 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001992 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001993 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001994
Johan Hedberg72a734e2010-12-30 00:38:22 +02001995 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001996
Johan Hedberg72a734e2010-12-30 00:38:22 +02001997 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001998
Szymon Janc4e51eae2011-02-25 19:05:48 +01001999 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000
2001 if (match.sk)
2002 sock_put(match.sk);
2003
2004 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002005}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002006
Johan Hedberg73f22f62010-12-29 16:00:25 +02002007int mgmt_discoverable(u16 index, u8 discoverable)
2008{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002009 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002010 struct cmd_lookup match = { discoverable, NULL };
2011 int ret;
2012
Szymon Jancb8534e02011-03-01 16:55:34 +01002013 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002014
Johan Hedberg72a734e2010-12-30 00:38:22 +02002015 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002016
Szymon Janc4e51eae2011-02-25 19:05:48 +01002017 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2018 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019
2020 if (match.sk)
2021 sock_put(match.sk);
2022
2023 return ret;
2024}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002025
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002026int mgmt_connectable(u16 index, u8 connectable)
2027{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002028 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002029 struct cmd_lookup match = { connectable, NULL };
2030 int ret;
2031
Johan Hedberg72a734e2010-12-30 00:38:22 +02002032 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002033
Johan Hedberg72a734e2010-12-30 00:38:22 +02002034 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002035
Szymon Janc4e51eae2011-02-25 19:05:48 +01002036 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002037
2038 if (match.sk)
2039 sock_put(match.sk);
2040
2041 return ret;
2042}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002043
Johan Hedberg4df378a2011-04-28 11:29:03 -07002044int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002045{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002046 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002047
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002048 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002049
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002050 ev.store_hint = persistent;
2051 bacpy(&ev.key.bdaddr, &key->bdaddr);
2052 ev.key.type = key->type;
2053 memcpy(ev.key.val, key->val, 16);
2054 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002055
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002056 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002057}
Johan Hedbergf7520542011-01-20 12:34:39 +02002058
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002059int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002060{
2061 struct mgmt_ev_connected ev;
2062
Johan Hedbergf7520542011-01-20 12:34:39 +02002063 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002064 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002065
Szymon Janc4e51eae2011-02-25 19:05:48 +01002066 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002067}
2068
Johan Hedberg8962ee72011-01-20 12:40:27 +02002069static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2070{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002071 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002072 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002073 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002074
Johan Hedberga38528f2011-01-22 06:46:43 +02002075 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002076
Szymon Janc4e51eae2011-02-25 19:05:48 +01002077 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002078
2079 *sk = cmd->sk;
2080 sock_hold(*sk);
2081
Johan Hedberga664b5b2011-02-19 12:06:02 -03002082 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002083}
2084
Johan Hedbergf7520542011-01-20 12:34:39 +02002085int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2086{
2087 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002088 struct sock *sk = NULL;
2089 int err;
2090
2091 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002092
Johan Hedbergf7520542011-01-20 12:34:39 +02002093 bacpy(&ev.bdaddr, bdaddr);
2094
Szymon Janc4e51eae2011-02-25 19:05:48 +01002095 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002096
2097 if (sk)
2098 sock_put(sk);
2099
2100 return err;
2101}
2102
2103int mgmt_disconnect_failed(u16 index)
2104{
2105 struct pending_cmd *cmd;
2106 int err;
2107
2108 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2109 if (!cmd)
2110 return -ENOENT;
2111
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113
Johan Hedberga664b5b2011-02-19 12:06:02 -03002114 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002115
2116 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002117}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002118
2119int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2120{
2121 struct mgmt_ev_connect_failed ev;
2122
Johan Hedberg17d5c042011-01-22 06:09:08 +02002123 bacpy(&ev.bdaddr, bdaddr);
2124 ev.status = status;
2125
Szymon Janc4e51eae2011-02-25 19:05:48 +01002126 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002127}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002128
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002129int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002130{
2131 struct mgmt_ev_pin_code_request ev;
2132
Johan Hedberg980e1a52011-01-22 06:10:07 +02002133 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002134 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002135
Szymon Janc4e51eae2011-02-25 19:05:48 +01002136 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2137 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138}
2139
2140int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2141{
2142 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002143 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002144 int err;
2145
2146 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2147 if (!cmd)
2148 return -ENOENT;
2149
Johan Hedbergac56fb12011-02-19 12:05:59 -03002150 bacpy(&rp.bdaddr, bdaddr);
2151 rp.status = status;
2152
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2154 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002155
Johan Hedberga664b5b2011-02-19 12:06:02 -03002156 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002157
2158 return err;
2159}
2160
2161int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2162{
2163 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002164 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002165 int err;
2166
2167 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2168 if (!cmd)
2169 return -ENOENT;
2170
Johan Hedbergac56fb12011-02-19 12:05:59 -03002171 bacpy(&rp.bdaddr, bdaddr);
2172 rp.status = status;
2173
Szymon Janc4e51eae2011-02-25 19:05:48 +01002174 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2175 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176
Johan Hedberga664b5b2011-02-19 12:06:02 -03002177 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002178
2179 return err;
2180}
Johan Hedberga5c29682011-02-19 12:05:57 -03002181
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002182int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2183 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002184{
2185 struct mgmt_ev_user_confirm_request ev;
2186
2187 BT_DBG("hci%u", index);
2188
Johan Hedberga5c29682011-02-19 12:05:57 -03002189 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002190 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002191 put_unaligned_le32(value, &ev.value);
2192
Szymon Janc4e51eae2011-02-25 19:05:48 +01002193 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2194 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002195}
2196
2197static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2198 u8 opcode)
2199{
2200 struct pending_cmd *cmd;
2201 struct mgmt_rp_user_confirm_reply rp;
2202 int err;
2203
2204 cmd = mgmt_pending_find(opcode, index);
2205 if (!cmd)
2206 return -ENOENT;
2207
Johan Hedberga5c29682011-02-19 12:05:57 -03002208 bacpy(&rp.bdaddr, bdaddr);
2209 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002210 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002211
Johan Hedberga664b5b2011-02-19 12:06:02 -03002212 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002213
2214 return err;
2215}
2216
2217int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2218{
2219 return confirm_reply_complete(index, bdaddr, status,
2220 MGMT_OP_USER_CONFIRM_REPLY);
2221}
2222
Szymon Jancb8534e02011-03-01 16:55:34 +01002223int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002224{
2225 return confirm_reply_complete(index, bdaddr, status,
2226 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2227}
Johan Hedberg2a611692011-02-19 12:06:00 -03002228
2229int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2230{
2231 struct mgmt_ev_auth_failed ev;
2232
Johan Hedberg2a611692011-02-19 12:06:00 -03002233 bacpy(&ev.bdaddr, bdaddr);
2234 ev.status = status;
2235
Szymon Janc4e51eae2011-02-25 19:05:48 +01002236 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002237}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002238
2239int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2240{
2241 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002242 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002243 struct mgmt_cp_set_local_name ev;
2244 int err;
2245
2246 memset(&ev, 0, sizeof(ev));
2247 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2248
2249 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2250 if (!cmd)
2251 goto send_event;
2252
2253 if (status) {
2254 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2255 goto failed;
2256 }
2257
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002258 hdev = hci_dev_get(index);
2259 if (hdev) {
2260 hci_dev_lock_bh(hdev);
2261 update_eir(hdev);
2262 hci_dev_unlock_bh(hdev);
2263 hci_dev_put(hdev);
2264 }
2265
Johan Hedbergb312b1612011-03-16 14:29:37 +02002266 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2267 sizeof(ev));
2268 if (err < 0)
2269 goto failed;
2270
2271send_event:
2272 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2273 cmd ? cmd->sk : NULL);
2274
2275failed:
2276 if (cmd)
2277 mgmt_pending_remove(cmd);
2278 return err;
2279}
Szymon Jancc35938b2011-03-22 13:12:21 +01002280
2281int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2282 u8 status)
2283{
2284 struct pending_cmd *cmd;
2285 int err;
2286
2287 BT_DBG("hci%u status %u", index, status);
2288
2289 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2290 if (!cmd)
2291 return -ENOENT;
2292
2293 if (status) {
2294 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2295 EIO);
2296 } else {
2297 struct mgmt_rp_read_local_oob_data rp;
2298
2299 memcpy(rp.hash, hash, sizeof(rp.hash));
2300 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2301
2302 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2303 &rp, sizeof(rp));
2304 }
2305
2306 mgmt_pending_remove(cmd);
2307
2308 return err;
2309}
Johan Hedberge17acd42011-03-30 23:57:16 +03002310
2311int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2312 u8 *eir)
2313{
2314 struct mgmt_ev_device_found ev;
2315
2316 memset(&ev, 0, sizeof(ev));
2317
2318 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002319 ev.rssi = rssi;
2320
2321 if (eir)
2322 memcpy(ev.eir, eir, sizeof(ev.eir));
2323
Andre Guedesf8523592011-09-09 18:56:26 -03002324 if (dev_class)
2325 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2326
Johan Hedberge17acd42011-03-30 23:57:16 +03002327 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2328}
Johan Hedberga88a9652011-03-30 13:18:12 +03002329
2330int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2331{
2332 struct mgmt_ev_remote_name ev;
2333
2334 memset(&ev, 0, sizeof(ev));
2335
2336 bacpy(&ev.bdaddr, bdaddr);
2337 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2338
2339 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2340}
Johan Hedberg314b2382011-04-27 10:29:57 -04002341
Johan Hedberg164a6e72011-11-01 17:06:44 +02002342int mgmt_inquiry_failed(u16 index, u8 status)
2343{
2344 struct pending_cmd *cmd;
2345 int err;
2346
2347 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2348 if (!cmd)
2349 return -ENOENT;
2350
2351 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2352 mgmt_pending_remove(cmd);
2353
2354 return err;
2355}
2356
Johan Hedberg314b2382011-04-27 10:29:57 -04002357int mgmt_discovering(u16 index, u8 discovering)
2358{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002359 struct pending_cmd *cmd;
2360
2361 if (discovering)
2362 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2363 else
2364 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2365
2366 if (cmd != NULL) {
2367 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2368 mgmt_pending_remove(cmd);
2369 }
2370
Johan Hedberg314b2382011-04-27 10:29:57 -04002371 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2372 sizeof(discovering), NULL);
2373}
Antti Julku5e762442011-08-25 16:48:02 +03002374
2375int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2376{
2377 struct pending_cmd *cmd;
2378 struct mgmt_ev_device_blocked ev;
2379
2380 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2381
2382 bacpy(&ev.bdaddr, bdaddr);
2383
2384 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2385 cmd ? cmd->sk : NULL);
2386}
2387
2388int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2389{
2390 struct pending_cmd *cmd;
2391 struct mgmt_ev_device_unblocked ev;
2392
2393 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2394
2395 bacpy(&ev.bdaddr, bdaddr);
2396
2397 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2398 cmd ? cmd->sk : NULL);
2399}