blob: 724d4fee2bd7960ef49e52e3fb1e1537848a2b7a [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
39 __u16 opcode;
40 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
Johannes Bergb5ad8b72011-06-01 08:54:45 +020046static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047
Szymon Janc4e51eae2011-02-25 19:05:48 +010048static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020049{
50 struct sk_buff *skb;
51 struct mgmt_hdr *hdr;
52 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030053 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +020054
Szymon Janc34eb5252011-02-28 14:10:08 +010055 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020056
57 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
58 if (!skb)
59 return -ENOMEM;
60
61 hdr = (void *) skb_put(skb, sizeof(*hdr));
62
63 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010064 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +020065 hdr->len = cpu_to_le16(sizeof(*ev));
66
67 ev = (void *) skb_put(skb, sizeof(*ev));
68 ev->status = status;
69 put_unaligned_le16(cmd, &ev->opcode);
70
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030071 err = sock_queue_rcv_skb(sk, skb);
72 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +020073 kfree_skb(skb);
74
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030075 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +020076}
77
Szymon Janc4e51eae2011-02-25 19:05:48 +010078static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
79 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020080{
81 struct sk_buff *skb;
82 struct mgmt_hdr *hdr;
83 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030084 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020085
86 BT_DBG("sock %p", sk);
87
Johan Hedberga38528f2011-01-22 06:46:43 +020088 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020089 if (!skb)
90 return -ENOMEM;
91
92 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020093
Johan Hedberg02d98122010-12-13 21:07:04 +020094 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010095 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020096 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020097
Johan Hedberga38528f2011-01-22 06:46:43 +020098 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
99 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100100
101 if (rp)
102 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200103
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300104 err = sock_queue_rcv_skb(sk, skb);
105 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 kfree_skb(skb);
107
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300108 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200109}
110
Johan Hedberga38528f2011-01-22 06:46:43 +0200111static int read_version(struct sock *sk)
112{
113 struct mgmt_rp_read_version rp;
114
115 BT_DBG("sock %p", sk);
116
117 rp.version = MGMT_VERSION;
118 put_unaligned_le16(MGMT_REVISION, &rp.revision);
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
121 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200122}
123
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124static int read_index_list(struct sock *sk)
125{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126 struct mgmt_rp_read_index_list *rp;
127 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200128 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200131 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132
133 BT_DBG("sock %p", sk);
134
135 read_lock(&hci_dev_list_lock);
136
137 count = 0;
138 list_for_each(p, &hci_dev_list) {
139 count++;
140 }
141
Johan Hedberga38528f2011-01-22 06:46:43 +0200142 rp_len = sizeof(*rp) + (2 * count);
143 rp = kmalloc(rp_len, GFP_ATOMIC);
144 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100147 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(count, &rp->num_controllers);
150
151 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200152 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200153 hci_del_off_timer(d);
154
155 if (test_bit(HCI_SETUP, &d->flags))
156 continue;
157
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200158 put_unaligned_le16(d->id, &rp->index[i++]);
159 BT_DBG("Added hci%u", d->id);
160 }
161
162 read_unlock(&hci_dev_list_lock);
163
Szymon Janc4e51eae2011-02-25 19:05:48 +0100164 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
165 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200166
Johan Hedberga38528f2011-01-22 06:46:43 +0200167 kfree(rp);
168
169 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200170}
171
Szymon Janc4e51eae2011-02-25 19:05:48 +0100172static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200173{
Johan Hedberga38528f2011-01-22 06:46:43 +0200174 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200202 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200215 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200216
Szymon Janc4e51eae2011-02-25 19:05:48 +0100217 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200218}
219
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220static void mgmt_pending_free(struct pending_cmd *cmd)
221{
222 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100223 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200224 kfree(cmd);
225}
226
Johan Hedberg366a0332011-02-19 12:05:55 -0300227static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
228 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200229{
230 struct pending_cmd *cmd;
231
232 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
233 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300234 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200235
236 cmd->opcode = opcode;
237 cmd->index = index;
238
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100239 cmd->param = kmalloc(len, GFP_ATOMIC);
240 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300242 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200243 }
244
Szymon Janc8fce6352011-03-22 13:12:20 +0100245 if (data)
246 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200247
248 cmd->sk = sk;
249 sock_hold(sk);
250
251 list_add(&cmd->list, &cmd_list);
252
Johan Hedberg366a0332011-02-19 12:05:55 -0300253 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200254}
255
256static void mgmt_pending_foreach(u16 opcode, int index,
257 void (*cb)(struct pending_cmd *cmd, void *data),
258 void *data)
259{
260 struct list_head *p, *n;
261
262 list_for_each_safe(p, n, &cmd_list) {
263 struct pending_cmd *cmd;
264
265 cmd = list_entry(p, struct pending_cmd, list);
266
Johan Hedbergb24752f2011-11-03 14:40:33 +0200267 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200268 continue;
269
270 if (index >= 0 && cmd->index != index)
271 continue;
272
273 cb(cmd, data);
274 }
275}
276
277static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
278{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200279 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200280
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200281 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282 if (cmd->opcode != opcode)
283 continue;
284
285 if (index >= 0 && cmd->index != index)
286 continue;
287
288 return cmd;
289 }
290
291 return NULL;
292}
293
Johan Hedberga664b5b2011-02-19 12:06:02 -0300294static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200295{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296 list_del(&cmd->list);
297 mgmt_pending_free(cmd);
298}
299
Szymon Janc4e51eae2011-02-25 19:05:48 +0100300static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200302 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300304 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
307 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100311 if (len != sizeof(*cp))
312 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
313
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317
Andre Guedes8c156c32011-07-07 10:30:36 -0300318 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
320 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200321 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100322 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200323 goto failed;
324 }
325
Szymon Janc4e51eae2011-02-25 19:05:48 +0100326 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
327 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
329 }
330
Szymon Janc4e51eae2011-02-25 19:05:48 +0100331 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300332 if (!cmd) {
333 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
Johan Hedberg72a734e2010-12-30 00:38:22 +0200337 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338 queue_work(hdev->workqueue, &hdev->power_on);
339 else
340 queue_work(hdev->workqueue, &hdev->power_off);
341
Johan Hedberg366a0332011-02-19 12:05:55 -0300342 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
344failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300345 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300347 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348}
349
Szymon Janc4e51eae2011-02-25 19:05:48 +0100350static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
351 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200353 struct mgmt_cp_set_discoverable *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;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200399 else
400 cancel_delayed_work_sync(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200401
402 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
403 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300404 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200405
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200406 if (cp->val)
407 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
408
Johan Hedberg73f22f62010-12-29 16:00:25 +0200409failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300410 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200411 hci_dev_put(hdev);
412
413 return err;
414}
415
Szymon Janc4e51eae2011-02-25 19:05:48 +0100416static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
417 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200419 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200420 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300421 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422 u8 scan;
423 int err;
424
425 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100429 if (len != sizeof(*cp))
430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
431
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435
Andre Guedes8c156c32011-07-07 10:30:36 -0300436 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437
438 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200440 goto failed;
441 }
442
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
444 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
445 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
447 }
448
Johan Hedberg72a734e2010-12-30 00:38:22 +0200449 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100450 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200451 goto failed;
452 }
453
Szymon Janc4e51eae2011-02-25 19:05:48 +0100454 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300455 if (!cmd) {
456 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300458 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459
Johan Hedberg72a734e2010-12-30 00:38:22 +0200460 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461 scan = SCAN_PAGE;
462 else
463 scan = 0;
464
465 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
466 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300467 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200468
469failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300470 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200471 hci_dev_put(hdev);
472
473 return err;
474}
475
Szymon Janc4e51eae2011-02-25 19:05:48 +0100476static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
477 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200478{
479 struct sk_buff *skb;
480 struct mgmt_hdr *hdr;
481
482 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
483 if (!skb)
484 return -ENOMEM;
485
486 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
487
488 hdr = (void *) skb_put(skb, sizeof(*hdr));
489 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100490 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491 hdr->len = cpu_to_le16(data_len);
492
Szymon Janc4e51eae2011-02-25 19:05:48 +0100493 if (data)
494 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200495
496 hci_send_to_sock(NULL, skb, skip_sk);
497 kfree_skb(skb);
498
499 return 0;
500}
501
Johan Hedberg053f0212011-01-26 13:07:10 +0200502static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
503{
Johan Hedberga38528f2011-01-22 06:46:43 +0200504 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200505
Johan Hedberga38528f2011-01-22 06:46:43 +0200506 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200507
Szymon Janc4e51eae2011-02-25 19:05:48 +0100508 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200509}
510
Szymon Janc4e51eae2011-02-25 19:05:48 +0100511static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
512 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200513{
514 struct mgmt_mode *cp, ev;
515 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200516 int err;
517
518 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100522 if (len != sizeof(*cp))
523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
524
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100527 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528
Andre Guedes8c156c32011-07-07 10:30:36 -0300529 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530
531 if (cp->val)
532 set_bit(HCI_PAIRABLE, &hdev->flags);
533 else
534 clear_bit(HCI_PAIRABLE, &hdev->flags);
535
Szymon Janc4e51eae2011-02-25 19:05:48 +0100536 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200537 if (err < 0)
538 goto failed;
539
Johan Hedbergc542a062011-01-26 13:11:03 +0200540 ev.val = cp->val;
541
Szymon Janc4e51eae2011-02-25 19:05:48 +0100542 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200543
544failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300545 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200546 hci_dev_put(hdev);
547
548 return err;
549}
550
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300551#define EIR_FLAGS 0x01 /* flags */
552#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
553#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
554#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
555#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
556#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
557#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
558#define EIR_NAME_SHORT 0x08 /* shortened local name */
559#define EIR_NAME_COMPLETE 0x09 /* complete local name */
560#define EIR_TX_POWER 0x0A /* transmit power level */
561#define EIR_DEVICE_ID 0x10 /* device ID */
562
563#define PNP_INFO_SVCLASS_ID 0x1200
564
565static u8 bluetooth_base_uuid[] = {
566 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
567 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568};
569
570static u16 get_uuid16(u8 *uuid128)
571{
572 u32 val;
573 int i;
574
575 for (i = 0; i < 12; i++) {
576 if (bluetooth_base_uuid[i] != uuid128[i])
577 return 0;
578 }
579
580 memcpy(&val, &uuid128[12], 4);
581
582 val = le32_to_cpu(val);
583 if (val > 0xffff)
584 return 0;
585
586 return (u16) val;
587}
588
589static void create_eir(struct hci_dev *hdev, u8 *data)
590{
591 u8 *ptr = data;
592 u16 eir_len = 0;
593 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
594 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200595 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300596 size_t name_len;
597
598 name_len = strlen(hdev->dev_name);
599
600 if (name_len > 0) {
601 /* EIR Data type */
602 if (name_len > 48) {
603 name_len = 48;
604 ptr[1] = EIR_NAME_SHORT;
605 } else
606 ptr[1] = EIR_NAME_COMPLETE;
607
608 /* EIR Data length */
609 ptr[0] = name_len + 1;
610
611 memcpy(ptr + 2, hdev->dev_name, name_len);
612
613 eir_len += (name_len + 2);
614 ptr += (name_len + 2);
615 }
616
617 memset(uuid16_list, 0, sizeof(uuid16_list));
618
619 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200620 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300621 u16 uuid16;
622
623 uuid16 = get_uuid16(uuid->uuid);
624 if (uuid16 == 0)
625 return;
626
627 if (uuid16 < 0x1100)
628 continue;
629
630 if (uuid16 == PNP_INFO_SVCLASS_ID)
631 continue;
632
633 /* Stop if not enough space to put next UUID */
634 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
635 truncated = 1;
636 break;
637 }
638
639 /* Check for duplicates */
640 for (i = 0; uuid16_list[i] != 0; i++)
641 if (uuid16_list[i] == uuid16)
642 break;
643
644 if (uuid16_list[i] == 0) {
645 uuid16_list[i] = uuid16;
646 eir_len += sizeof(u16);
647 }
648 }
649
650 if (uuid16_list[0] != 0) {
651 u8 *length = ptr;
652
653 /* EIR Data type */
654 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
655
656 ptr += 2;
657 eir_len += 2;
658
659 for (i = 0; uuid16_list[i] != 0; i++) {
660 *ptr++ = (uuid16_list[i] & 0x00ff);
661 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
662 }
663
664 /* EIR Data length */
665 *length = (i * sizeof(u16)) + 1;
666 }
667}
668
669static int update_eir(struct hci_dev *hdev)
670{
671 struct hci_cp_write_eir cp;
672
673 if (!(hdev->features[6] & LMP_EXT_INQ))
674 return 0;
675
676 if (hdev->ssp_mode == 0)
677 return 0;
678
679 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
680 return 0;
681
682 memset(&cp, 0, sizeof(cp));
683
684 create_eir(hdev, cp.data);
685
686 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
687 return 0;
688
689 memcpy(hdev->eir, cp.data, sizeof(cp.data));
690
691 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
692}
693
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200694static u8 get_service_classes(struct hci_dev *hdev)
695{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300696 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200697 u8 val = 0;
698
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300699 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200700 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200701
702 return val;
703}
704
705static int update_class(struct hci_dev *hdev)
706{
707 u8 cod[3];
708
709 BT_DBG("%s", hdev->name);
710
711 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
712 return 0;
713
714 cod[0] = hdev->minor_class;
715 cod[1] = hdev->major_class;
716 cod[2] = get_service_classes(hdev);
717
718 if (memcmp(cod, hdev->dev_class, 3) == 0)
719 return 0;
720
721 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
722}
723
Szymon Janc4e51eae2011-02-25 19:05:48 +0100724static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725{
726 struct mgmt_cp_add_uuid *cp;
727 struct hci_dev *hdev;
728 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729 int err;
730
731 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200732
Szymon Janc4e51eae2011-02-25 19:05:48 +0100733 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100735 if (len != sizeof(*cp))
736 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741
Andre Guedes8c156c32011-07-07 10:30:36 -0300742 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743
744 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
745 if (!uuid) {
746 err = -ENOMEM;
747 goto failed;
748 }
749
750 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200751 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200752
753 list_add(&uuid->list, &hdev->uuids);
754
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755 err = update_class(hdev);
756 if (err < 0)
757 goto failed;
758
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300759 err = update_eir(hdev);
760 if (err < 0)
761 goto failed;
762
Szymon Janc4e51eae2011-02-25 19:05:48 +0100763 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200764
765failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300766 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200767 hci_dev_put(hdev);
768
769 return err;
770}
771
Szymon Janc4e51eae2011-02-25 19:05:48 +0100772static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200773{
774 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100775 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200776 struct hci_dev *hdev;
777 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 +0200778 int err, found;
779
780 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781
Szymon Janc4e51eae2011-02-25 19:05:48 +0100782 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100784 if (len != sizeof(*cp))
785 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
786
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100789 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790
Andre Guedes8c156c32011-07-07 10:30:36 -0300791 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792
793 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
794 err = hci_uuids_clear(hdev);
795 goto unlock;
796 }
797
798 found = 0;
799
800 list_for_each_safe(p, n, &hdev->uuids) {
801 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
802
803 if (memcmp(match->uuid, cp->uuid, 16) != 0)
804 continue;
805
806 list_del(&match->list);
807 found++;
808 }
809
810 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200812 goto unlock;
813 }
814
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200815 err = update_class(hdev);
816 if (err < 0)
817 goto unlock;
818
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300819 err = update_eir(hdev);
820 if (err < 0)
821 goto unlock;
822
Szymon Janc4e51eae2011-02-25 19:05:48 +0100823 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200824
825unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300826 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200827 hci_dev_put(hdev);
828
829 return err;
830}
831
Szymon Janc4e51eae2011-02-25 19:05:48 +0100832static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
833 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200834{
835 struct hci_dev *hdev;
836 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200837 int err;
838
839 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100843 if (len != sizeof(*cp))
844 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
845
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849
Andre Guedes8c156c32011-07-07 10:30:36 -0300850 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851
852 hdev->major_class = cp->major;
853 hdev->minor_class = cp->minor;
854
855 err = update_class(hdev);
856
857 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100858 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200859
Andre Guedes8c156c32011-07-07 10:30:36 -0300860 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861 hci_dev_put(hdev);
862
863 return err;
864}
865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
867 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200868{
869 struct hci_dev *hdev;
870 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200871 int err;
872
873 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200874
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100875 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100876 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100877
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
Andre Guedes8c156c32011-07-07 10:30:36 -0300882 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
886 if (cp->enable) {
887 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
888 err = 0;
889 } else {
890 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
891 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300892 if (err == 0)
893 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200894 }
895
896 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100897 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
898 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300899 else
900 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
901
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902
Andre Guedes8c156c32011-07-07 10:30:36 -0300903 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904 hci_dev_put(hdev);
905
906 return err;
907}
908
Szymon Janc4e51eae2011-02-25 19:05:48 +0100909static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200910{
911 struct hci_dev *hdev;
912 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100913 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300914 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200915
916 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100917
918 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300919 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100920
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200921 key_count = get_unaligned_le16(&cp->key_count);
922
923 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300924 if (expected_len != len) {
925 BT_ERR("load_keys: expected %u bytes, got %u bytes",
926 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300927 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928 }
929
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935 key_count);
936
Andre Guedes8c156c32011-07-07 10:30:36 -0300937 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200938
939 hci_link_keys_clear(hdev);
940
941 set_bit(HCI_LINK_KEYS, &hdev->flags);
942
943 if (cp->debug_keys)
944 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
945 else
946 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
947
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300948 for (i = 0; i < key_count; i++) {
949 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700951 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200952 key->pin_len);
953 }
954
Andre Guedes8c156c32011-07-07 10:30:36 -0300955 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200956 hci_dev_put(hdev);
957
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300958 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200959}
960
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200962{
963 struct hci_dev *hdev;
964 struct mgmt_cp_remove_key *cp;
965 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200966 int err;
967
968 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200969
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100970 if (len != sizeof(*cp))
971 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
972
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200976
Andre Guedes8c156c32011-07-07 10:30:36 -0300977 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978
979 err = hci_remove_link_key(hdev, &cp->bdaddr);
980 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100981 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200982 goto unlock;
983 }
984
985 err = 0;
986
987 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
988 goto unlock;
989
990 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
991 if (conn) {
992 struct hci_cp_disconnect dc;
993
994 put_unaligned_le16(conn->handle, &dc.handle);
995 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400996 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200997 }
998
999unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001000 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001001 hci_dev_put(hdev);
1002
1003 return err;
1004}
1005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001007{
1008 struct hci_dev *hdev;
1009 struct mgmt_cp_disconnect *cp;
1010 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001011 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001012 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001013 int err;
1014
1015 BT_DBG("");
1016
1017 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001018
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001019 if (len != sizeof(*cp))
1020 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1021
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025
Andre Guedes8c156c32011-07-07 10:30:36 -03001026 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001027
1028 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001030 goto failed;
1031 }
1032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1034 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001035 goto failed;
1036 }
1037
1038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001039 if (!conn)
1040 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1041
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001043 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001044 goto failed;
1045 }
1046
Szymon Janc4e51eae2011-02-25 19:05:48 +01001047 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001048 if (!cmd) {
1049 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001050 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001051 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001052
1053 put_unaligned_le16(conn->handle, &dc.handle);
1054 dc.reason = 0x13; /* Remote User Terminated Connection */
1055
1056 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1057 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001058 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059
1060failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001061 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001062 hci_dev_put(hdev);
1063
1064 return err;
1065}
1066
Szymon Janc8ce62842011-03-01 16:55:32 +01001067static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001068{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001069 struct mgmt_rp_get_connections *rp;
1070 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001071 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001072 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001073 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001075 int i, err;
1076
1077 BT_DBG("");
1078
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001080 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001082
Andre Guedes8c156c32011-07-07 10:30:36 -03001083 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001084
1085 count = 0;
1086 list_for_each(p, &hdev->conn_hash.list) {
1087 count++;
1088 }
1089
Johan Hedberga38528f2011-01-22 06:46:43 +02001090 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1091 rp = kmalloc(rp_len, GFP_ATOMIC);
1092 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001093 err = -ENOMEM;
1094 goto unlock;
1095 }
1096
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097 put_unaligned_le16(count, &rp->conn_count);
1098
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001100 list_for_each_entry(c, &hdev->conn_hash.list, list)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001101 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001102
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104
1105unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001106 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001107 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001108 hci_dev_put(hdev);
1109 return err;
1110}
1111
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001112static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1113 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1114{
1115 struct pending_cmd *cmd;
1116 int err;
1117
1118 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1119 sizeof(*cp));
1120 if (!cmd)
1121 return -ENOMEM;
1122
1123 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1124 &cp->bdaddr);
1125 if (err < 0)
1126 mgmt_pending_remove(cmd);
1127
1128 return err;
1129}
1130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1132 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001133{
1134 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001135 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001137 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001139 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001140 int err;
1141
1142 BT_DBG("");
1143
1144 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146 if (len != sizeof(*cp))
1147 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152
Andre Guedes8c156c32011-07-07 10:30:36 -03001153 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154
1155 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001157 goto failed;
1158 }
1159
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001160 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1161 if (!conn) {
1162 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1163 goto failed;
1164 }
1165
1166 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1167 bacpy(&ncp.bdaddr, &cp->bdaddr);
1168
1169 BT_ERR("PIN code is not 16 bytes long");
1170
1171 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1172 if (err >= 0)
1173 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1174 EINVAL);
1175
1176 goto failed;
1177 }
1178
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 if (!cmd) {
1181 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001183 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184
1185 bacpy(&reply.bdaddr, &cp->bdaddr);
1186 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001187 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188
1189 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1190 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001191 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001192
1193failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001194 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 hci_dev_put(hdev);
1196
1197 return err;
1198}
1199
Szymon Janc4e51eae2011-02-25 19:05:48 +01001200static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1201 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202{
1203 struct hci_dev *hdev;
1204 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205 int err;
1206
1207 BT_DBG("");
1208
1209 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001211 if (len != sizeof(*cp))
1212 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1213 EINVAL);
1214
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001216 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1218 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219
Andre Guedes8c156c32011-07-07 10:30:36 -03001220 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221
1222 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001223 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1224 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001225 goto failed;
1226 }
1227
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001228 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001229
1230failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001231 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232 hci_dev_put(hdev);
1233
1234 return err;
1235}
1236
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1238 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001239{
1240 struct hci_dev *hdev;
1241 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001242
1243 BT_DBG("");
1244
1245 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001246
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001247 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001248 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001249
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001251 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253
Andre Guedes8c156c32011-07-07 10:30:36 -03001254 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255
1256 hdev->io_capability = cp->io_capability;
1257
1258 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001259 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260
Andre Guedes8c156c32011-07-07 10:30:36 -03001261 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001262 hci_dev_put(hdev);
1263
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265}
1266
Johan Hedberge9a416b2011-02-19 12:05:56 -03001267static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1268{
1269 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001270 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001271
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001272 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001273 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1274 continue;
1275
1276 if (cmd->index != hdev->id)
1277 continue;
1278
1279 if (cmd->user_data != conn)
1280 continue;
1281
1282 return cmd;
1283 }
1284
1285 return NULL;
1286}
1287
1288static void pairing_complete(struct pending_cmd *cmd, u8 status)
1289{
1290 struct mgmt_rp_pair_device rp;
1291 struct hci_conn *conn = cmd->user_data;
1292
Johan Hedberge9a416b2011-02-19 12:05:56 -03001293 bacpy(&rp.bdaddr, &conn->dst);
1294 rp.status = status;
1295
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001297
1298 /* So we don't get further callbacks for this connection */
1299 conn->connect_cfm_cb = NULL;
1300 conn->security_cfm_cb = NULL;
1301 conn->disconn_cfm_cb = NULL;
1302
1303 hci_conn_put(conn);
1304
Johan Hedberga664b5b2011-02-19 12:06:02 -03001305 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001306}
1307
1308static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1309{
1310 struct pending_cmd *cmd;
1311
1312 BT_DBG("status %u", status);
1313
1314 cmd = find_pairing(conn);
1315 if (!cmd) {
1316 BT_DBG("Unable to find a pending command");
1317 return;
1318 }
1319
1320 pairing_complete(cmd, status);
1321}
1322
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324{
1325 struct hci_dev *hdev;
1326 struct mgmt_cp_pair_device *cp;
1327 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001328 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001329 u8 sec_level, auth_type;
1330 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331 int err;
1332
1333 BT_DBG("");
1334
1335 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001337 if (len != sizeof(*cp))
1338 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001341 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
Andre Guedes8c156c32011-07-07 10:30:36 -03001344 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001346 sec_level = BT_SECURITY_MEDIUM;
1347 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001348 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001349 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001351
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001352 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1353 if (entry)
1354 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1355 auth_type);
1356 else
1357 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1358 auth_type);
1359
Ville Tervo30e76272011-02-22 16:10:53 -03001360 if (IS_ERR(conn)) {
1361 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001362 goto unlock;
1363 }
1364
1365 if (conn->connect_cfm_cb) {
1366 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001368 goto unlock;
1369 }
1370
Szymon Janc4e51eae2011-02-25 19:05:48 +01001371 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 if (!cmd) {
1373 err = -ENOMEM;
1374 hci_conn_put(conn);
1375 goto unlock;
1376 }
1377
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001378 /* For LE, just connecting isn't a proof that the pairing finished */
1379 if (!entry)
1380 conn->connect_cfm_cb = pairing_complete_cb;
1381
Johan Hedberge9a416b2011-02-19 12:05:56 -03001382 conn->security_cfm_cb = pairing_complete_cb;
1383 conn->disconn_cfm_cb = pairing_complete_cb;
1384 conn->io_capability = cp->io_cap;
1385 cmd->user_data = conn;
1386
1387 if (conn->state == BT_CONNECTED &&
1388 hci_conn_security(conn, sec_level, auth_type))
1389 pairing_complete(cmd, 0);
1390
1391 err = 0;
1392
1393unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001394 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001395 hci_dev_put(hdev);
1396
1397 return err;
1398}
1399
Szymon Janc4e51eae2011-02-25 19:05:48 +01001400static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1401 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001402{
1403 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001404 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001405 struct pending_cmd *cmd;
1406 struct hci_dev *hdev;
1407 int err;
1408
1409 BT_DBG("");
1410
Johan Hedberga5c29682011-02-19 12:05:57 -03001411 if (success) {
1412 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1413 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1414 } else {
1415 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1416 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1417 }
1418
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001419 if (len != sizeof(*cp))
1420 return cmd_status(sk, index, mgmt_op, EINVAL);
1421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001423 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001425
Andre Guedes8c156c32011-07-07 10:30:36 -03001426 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001427
Johan Hedberga5c29682011-02-19 12:05:57 -03001428 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001430 goto failed;
1431 }
1432
Szymon Janc4e51eae2011-02-25 19:05:48 +01001433 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001434 if (!cmd) {
1435 err = -ENOMEM;
1436 goto failed;
1437 }
1438
1439 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001440 if (err < 0)
1441 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001442
1443failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001444 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001445 hci_dev_put(hdev);
1446
1447 return err;
1448}
1449
Johan Hedbergb312b1612011-03-16 14:29:37 +02001450static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1451 u16 len)
1452{
1453 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1454 struct hci_cp_write_local_name hci_cp;
1455 struct hci_dev *hdev;
1456 struct pending_cmd *cmd;
1457 int err;
1458
1459 BT_DBG("");
1460
1461 if (len != sizeof(*mgmt_cp))
1462 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1463
1464 hdev = hci_dev_get(index);
1465 if (!hdev)
1466 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1467
Andre Guedes8c156c32011-07-07 10:30:36 -03001468 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001469
1470 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1471 if (!cmd) {
1472 err = -ENOMEM;
1473 goto failed;
1474 }
1475
1476 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1477 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1478 &hci_cp);
1479 if (err < 0)
1480 mgmt_pending_remove(cmd);
1481
1482failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001483 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001484 hci_dev_put(hdev);
1485
1486 return err;
1487}
1488
Szymon Jancc35938b2011-03-22 13:12:21 +01001489static int read_local_oob_data(struct sock *sk, u16 index)
1490{
1491 struct hci_dev *hdev;
1492 struct pending_cmd *cmd;
1493 int err;
1494
1495 BT_DBG("hci%u", index);
1496
1497 hdev = hci_dev_get(index);
1498 if (!hdev)
1499 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1500 ENODEV);
1501
Andre Guedes8c156c32011-07-07 10:30:36 -03001502 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001503
1504 if (!test_bit(HCI_UP, &hdev->flags)) {
1505 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1506 ENETDOWN);
1507 goto unlock;
1508 }
1509
1510 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1511 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1512 EOPNOTSUPP);
1513 goto unlock;
1514 }
1515
1516 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1517 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1518 goto unlock;
1519 }
1520
1521 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1522 if (!cmd) {
1523 err = -ENOMEM;
1524 goto unlock;
1525 }
1526
1527 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1528 if (err < 0)
1529 mgmt_pending_remove(cmd);
1530
1531unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001532 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001533 hci_dev_put(hdev);
1534
1535 return err;
1536}
1537
Szymon Janc2763eda2011-03-22 13:12:22 +01001538static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1539 u16 len)
1540{
1541 struct hci_dev *hdev;
1542 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1543 int err;
1544
1545 BT_DBG("hci%u ", index);
1546
1547 if (len != sizeof(*cp))
1548 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1549 EINVAL);
1550
1551 hdev = hci_dev_get(index);
1552 if (!hdev)
1553 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1554 ENODEV);
1555
Andre Guedes8c156c32011-07-07 10:30:36 -03001556 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001557
1558 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1559 cp->randomizer);
1560 if (err < 0)
1561 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1562 else
1563 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1564 0);
1565
Andre Guedes8c156c32011-07-07 10:30:36 -03001566 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001567 hci_dev_put(hdev);
1568
1569 return err;
1570}
1571
1572static int remove_remote_oob_data(struct sock *sk, u16 index,
1573 unsigned char *data, u16 len)
1574{
1575 struct hci_dev *hdev;
1576 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1577 int err;
1578
1579 BT_DBG("hci%u ", index);
1580
1581 if (len != sizeof(*cp))
1582 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1583 EINVAL);
1584
1585 hdev = hci_dev_get(index);
1586 if (!hdev)
1587 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1588 ENODEV);
1589
Andre Guedes8c156c32011-07-07 10:30:36 -03001590 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001591
1592 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1593 if (err < 0)
1594 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1595 -err);
1596 else
1597 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1598 NULL, 0);
1599
Andre Guedes8c156c32011-07-07 10:30:36 -03001600 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001601 hci_dev_put(hdev);
1602
1603 return err;
1604}
1605
Johan Hedberg14a53662011-04-27 10:29:56 -04001606static int start_discovery(struct sock *sk, u16 index)
1607{
Johan Hedberg14a53662011-04-27 10:29:56 -04001608 struct pending_cmd *cmd;
1609 struct hci_dev *hdev;
1610 int err;
1611
1612 BT_DBG("hci%u", index);
1613
1614 hdev = hci_dev_get(index);
1615 if (!hdev)
1616 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1617
1618 hci_dev_lock_bh(hdev);
1619
1620 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1621 if (!cmd) {
1622 err = -ENOMEM;
1623 goto failed;
1624 }
1625
Andre Guedes2519a1f2011-11-07 11:45:24 -03001626 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001627 if (err < 0)
1628 mgmt_pending_remove(cmd);
1629
1630failed:
1631 hci_dev_unlock_bh(hdev);
1632 hci_dev_put(hdev);
1633
1634 return err;
1635}
1636
1637static int stop_discovery(struct sock *sk, u16 index)
1638{
1639 struct hci_dev *hdev;
1640 struct pending_cmd *cmd;
1641 int err;
1642
1643 BT_DBG("hci%u", index);
1644
1645 hdev = hci_dev_get(index);
1646 if (!hdev)
1647 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1648
1649 hci_dev_lock_bh(hdev);
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1652 if (!cmd) {
1653 err = -ENOMEM;
1654 goto failed;
1655 }
1656
Andre Guedes023d50492011-11-04 14:16:52 -03001657 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001658 if (err < 0)
1659 mgmt_pending_remove(cmd);
1660
1661failed:
1662 hci_dev_unlock_bh(hdev);
1663 hci_dev_put(hdev);
1664
1665 return err;
1666}
1667
Antti Julku7fbec222011-06-15 12:01:15 +03001668static int block_device(struct sock *sk, u16 index, unsigned char *data,
1669 u16 len)
1670{
1671 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001672 struct pending_cmd *cmd;
1673 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001674 int err;
1675
1676 BT_DBG("hci%u", index);
1677
Antti Julku7fbec222011-06-15 12:01:15 +03001678 if (len != sizeof(*cp))
1679 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1680 EINVAL);
1681
1682 hdev = hci_dev_get(index);
1683 if (!hdev)
1684 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1685 ENODEV);
1686
Antti Julku5e762442011-08-25 16:48:02 +03001687 hci_dev_lock_bh(hdev);
1688
1689 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1690 if (!cmd) {
1691 err = -ENOMEM;
1692 goto failed;
1693 }
1694
Antti Julku7fbec222011-06-15 12:01:15 +03001695 err = hci_blacklist_add(hdev, &cp->bdaddr);
1696
1697 if (err < 0)
1698 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1699 else
1700 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1701 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001702
1703 mgmt_pending_remove(cmd);
1704
1705failed:
1706 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001707 hci_dev_put(hdev);
1708
1709 return err;
1710}
1711
1712static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1713 u16 len)
1714{
1715 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001716 struct pending_cmd *cmd;
1717 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001718 int err;
1719
1720 BT_DBG("hci%u", index);
1721
Antti Julku7fbec222011-06-15 12:01:15 +03001722 if (len != sizeof(*cp))
1723 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1724 EINVAL);
1725
1726 hdev = hci_dev_get(index);
1727 if (!hdev)
1728 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1729 ENODEV);
1730
Antti Julku5e762442011-08-25 16:48:02 +03001731 hci_dev_lock_bh(hdev);
1732
1733 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1734 if (!cmd) {
1735 err = -ENOMEM;
1736 goto failed;
1737 }
1738
Antti Julku7fbec222011-06-15 12:01:15 +03001739 err = hci_blacklist_del(hdev, &cp->bdaddr);
1740
1741 if (err < 0)
1742 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1743 else
1744 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1745 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001746
1747 mgmt_pending_remove(cmd);
1748
1749failed:
1750 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001751 hci_dev_put(hdev);
1752
1753 return err;
1754}
1755
Antti Julkuf6422ec2011-06-22 13:11:56 +03001756static int set_fast_connectable(struct sock *sk, u16 index,
1757 unsigned char *data, u16 len)
1758{
1759 struct hci_dev *hdev;
1760 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1761 struct hci_cp_write_page_scan_activity acp;
1762 u8 type;
1763 int err;
1764
1765 BT_DBG("hci%u", index);
1766
1767 if (len != sizeof(*cp))
1768 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1769 EINVAL);
1770
1771 hdev = hci_dev_get(index);
1772 if (!hdev)
1773 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1774 ENODEV);
1775
1776 hci_dev_lock(hdev);
1777
1778 if (cp->enable) {
1779 type = PAGE_SCAN_TYPE_INTERLACED;
1780 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1781 } else {
1782 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1783 acp.interval = 0x0800; /* default 1.28 sec page scan */
1784 }
1785
1786 acp.window = 0x0012; /* default 11.25 msec page scan window */
1787
1788 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1789 sizeof(acp), &acp);
1790 if (err < 0) {
1791 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1792 -err);
1793 goto done;
1794 }
1795
1796 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1797 if (err < 0) {
1798 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1799 -err);
1800 goto done;
1801 }
1802
1803 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1804 NULL, 0);
1805done:
1806 hci_dev_unlock(hdev);
1807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Johan Hedberg03811012010-12-08 00:21:06 +02001812int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1813{
1814 unsigned char *buf;
1815 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001816 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001817 int err;
1818
1819 BT_DBG("got %zu bytes", msglen);
1820
1821 if (msglen < sizeof(*hdr))
1822 return -EINVAL;
1823
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001824 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001825 if (!buf)
1826 return -ENOMEM;
1827
1828 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1829 err = -EFAULT;
1830 goto done;
1831 }
1832
1833 hdr = (struct mgmt_hdr *) buf;
1834 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001835 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001836 len = get_unaligned_le16(&hdr->len);
1837
1838 if (len != msglen - sizeof(*hdr)) {
1839 err = -EINVAL;
1840 goto done;
1841 }
1842
1843 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001844 case MGMT_OP_READ_VERSION:
1845 err = read_version(sk);
1846 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001847 case MGMT_OP_READ_INDEX_LIST:
1848 err = read_index_list(sk);
1849 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001850 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001851 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001852 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001853 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001854 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001855 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001856 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001857 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001858 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001859 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001861 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001862 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001864 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001865 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001867 break;
1868 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001870 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001871 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001873 break;
1874 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001876 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001877 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 break;
1880 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001882 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001883 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001885 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001886 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001887 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001888 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001891 break;
1892 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001894 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001895 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001897 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001901 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001903 break;
1904 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001906 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001907 case MGMT_OP_SET_LOCAL_NAME:
1908 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1909 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001910 case MGMT_OP_READ_LOCAL_OOB_DATA:
1911 err = read_local_oob_data(sk, index);
1912 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001913 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1914 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1915 break;
1916 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1917 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1918 len);
1919 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001920 case MGMT_OP_START_DISCOVERY:
1921 err = start_discovery(sk, index);
1922 break;
1923 case MGMT_OP_STOP_DISCOVERY:
1924 err = stop_discovery(sk, index);
1925 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001926 case MGMT_OP_BLOCK_DEVICE:
1927 err = block_device(sk, index, buf + sizeof(*hdr), len);
1928 break;
1929 case MGMT_OP_UNBLOCK_DEVICE:
1930 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1931 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001932 case MGMT_OP_SET_FAST_CONNECTABLE:
1933 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1934 len);
1935 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001936 default:
1937 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001938 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001939 break;
1940 }
1941
Johan Hedberge41d8b42010-12-13 21:07:03 +02001942 if (err < 0)
1943 goto done;
1944
Johan Hedberg03811012010-12-08 00:21:06 +02001945 err = msglen;
1946
1947done:
1948 kfree(buf);
1949 return err;
1950}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001951
Johan Hedbergb24752f2011-11-03 14:40:33 +02001952static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1953{
1954 u8 *status = data;
1955
1956 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1957 mgmt_pending_remove(cmd);
1958}
1959
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001960int mgmt_index_added(u16 index)
1961{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001962 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001963}
1964
1965int mgmt_index_removed(u16 index)
1966{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001967 u8 status = ENODEV;
1968
1969 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1970
Szymon Janc4e51eae2011-02-25 19:05:48 +01001971 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001972}
1973
Johan Hedberg73f22f62010-12-29 16:00:25 +02001974struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001975 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001976 struct sock *sk;
1977};
1978
Johan Hedberg72a734e2010-12-30 00:38:22 +02001979static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001980{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001981 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001982 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001983
Johan Hedberg72a734e2010-12-30 00:38:22 +02001984 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985 return;
1986
Johan Hedberg053f0212011-01-26 13:07:10 +02001987 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001988
1989 list_del(&cmd->list);
1990
1991 if (match->sk == NULL) {
1992 match->sk = cmd->sk;
1993 sock_hold(match->sk);
1994 }
1995
1996 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001997}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001998
1999int mgmt_powered(u16 index, u8 powered)
2000{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002001 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002002 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002003 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002004
Johan Hedberg72a734e2010-12-30 00:38:22 +02002005 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002006
Johan Hedbergb24752f2011-11-03 14:40:33 +02002007 if (!powered) {
2008 u8 status = ENETDOWN;
2009 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2010 }
2011
Johan Hedberg72a734e2010-12-30 00:38:22 +02002012 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013
Szymon Janc4e51eae2011-02-25 19:05:48 +01002014 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015
2016 if (match.sk)
2017 sock_put(match.sk);
2018
2019 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002020}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002021
Johan Hedberg73f22f62010-12-29 16:00:25 +02002022int mgmt_discoverable(u16 index, u8 discoverable)
2023{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002025 struct cmd_lookup match = { discoverable, NULL };
2026 int ret;
2027
Szymon Jancb8534e02011-03-01 16:55:34 +01002028 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002029
Johan Hedberg72a734e2010-12-30 00:38:22 +02002030 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002031
Szymon Janc4e51eae2011-02-25 19:05:48 +01002032 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2033 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002034
2035 if (match.sk)
2036 sock_put(match.sk);
2037
2038 return ret;
2039}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002040
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002041int mgmt_connectable(u16 index, u8 connectable)
2042{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002043 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002044 struct cmd_lookup match = { connectable, NULL };
2045 int ret;
2046
Johan Hedberg72a734e2010-12-30 00:38:22 +02002047 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002048
Johan Hedberg72a734e2010-12-30 00:38:22 +02002049 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002050
Szymon Janc4e51eae2011-02-25 19:05:48 +01002051 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052
2053 if (match.sk)
2054 sock_put(match.sk);
2055
2056 return ret;
2057}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058
Johan Hedberg4df378a2011-04-28 11:29:03 -07002059int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002060{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002061 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002062
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002063 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002065 ev.store_hint = persistent;
2066 bacpy(&ev.key.bdaddr, &key->bdaddr);
2067 ev.key.type = key->type;
2068 memcpy(ev.key.val, key->val, 16);
2069 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002070
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002071 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002072}
Johan Hedbergf7520542011-01-20 12:34:39 +02002073
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002074int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002075{
2076 struct mgmt_ev_connected ev;
2077
Johan Hedbergf7520542011-01-20 12:34:39 +02002078 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002079 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002080
Szymon Janc4e51eae2011-02-25 19:05:48 +01002081 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002082}
2083
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2085{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002086 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002087 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002088 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002089
Johan Hedberga38528f2011-01-22 06:46:43 +02002090 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091
Szymon Janc4e51eae2011-02-25 19:05:48 +01002092 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002093
2094 *sk = cmd->sk;
2095 sock_hold(*sk);
2096
Johan Hedberga664b5b2011-02-19 12:06:02 -03002097 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002098}
2099
Johan Hedbergf7520542011-01-20 12:34:39 +02002100int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2101{
2102 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002103 struct sock *sk = NULL;
2104 int err;
2105
2106 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002107
Johan Hedbergf7520542011-01-20 12:34:39 +02002108 bacpy(&ev.bdaddr, bdaddr);
2109
Szymon Janc4e51eae2011-02-25 19:05:48 +01002110 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002111
2112 if (sk)
2113 sock_put(sk);
2114
2115 return err;
2116}
2117
2118int mgmt_disconnect_failed(u16 index)
2119{
2120 struct pending_cmd *cmd;
2121 int err;
2122
2123 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2124 if (!cmd)
2125 return -ENOENT;
2126
Szymon Janc4e51eae2011-02-25 19:05:48 +01002127 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002128
Johan Hedberga664b5b2011-02-19 12:06:02 -03002129 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002130
2131 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002132}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002133
2134int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2135{
2136 struct mgmt_ev_connect_failed ev;
2137
Johan Hedberg17d5c042011-01-22 06:09:08 +02002138 bacpy(&ev.bdaddr, bdaddr);
2139 ev.status = status;
2140
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002142}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002144int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145{
2146 struct mgmt_ev_pin_code_request ev;
2147
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002149 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150
Szymon Janc4e51eae2011-02-25 19:05:48 +01002151 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2152 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002153}
2154
2155int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2156{
2157 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002158 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002159 int err;
2160
2161 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2162 if (!cmd)
2163 return -ENOENT;
2164
Johan Hedbergac56fb12011-02-19 12:05:59 -03002165 bacpy(&rp.bdaddr, bdaddr);
2166 rp.status = status;
2167
Szymon Janc4e51eae2011-02-25 19:05:48 +01002168 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2169 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002170
Johan Hedberga664b5b2011-02-19 12:06:02 -03002171 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172
2173 return err;
2174}
2175
2176int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2177{
2178 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002179 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180 int err;
2181
2182 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2183 if (!cmd)
2184 return -ENOENT;
2185
Johan Hedbergac56fb12011-02-19 12:05:59 -03002186 bacpy(&rp.bdaddr, bdaddr);
2187 rp.status = status;
2188
Szymon Janc4e51eae2011-02-25 19:05:48 +01002189 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2190 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191
Johan Hedberga664b5b2011-02-19 12:06:02 -03002192 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002193
2194 return err;
2195}
Johan Hedberga5c29682011-02-19 12:05:57 -03002196
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002197int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2198 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002199{
2200 struct mgmt_ev_user_confirm_request ev;
2201
2202 BT_DBG("hci%u", index);
2203
Johan Hedberga5c29682011-02-19 12:05:57 -03002204 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002205 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002206 put_unaligned_le32(value, &ev.value);
2207
Szymon Janc4e51eae2011-02-25 19:05:48 +01002208 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2209 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002210}
2211
2212static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2213 u8 opcode)
2214{
2215 struct pending_cmd *cmd;
2216 struct mgmt_rp_user_confirm_reply rp;
2217 int err;
2218
2219 cmd = mgmt_pending_find(opcode, index);
2220 if (!cmd)
2221 return -ENOENT;
2222
Johan Hedberga5c29682011-02-19 12:05:57 -03002223 bacpy(&rp.bdaddr, bdaddr);
2224 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002225 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002226
Johan Hedberga664b5b2011-02-19 12:06:02 -03002227 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002228
2229 return err;
2230}
2231
2232int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2233{
2234 return confirm_reply_complete(index, bdaddr, status,
2235 MGMT_OP_USER_CONFIRM_REPLY);
2236}
2237
Szymon Jancb8534e02011-03-01 16:55:34 +01002238int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002239{
2240 return confirm_reply_complete(index, bdaddr, status,
2241 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2242}
Johan Hedberg2a611692011-02-19 12:06:00 -03002243
2244int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2245{
2246 struct mgmt_ev_auth_failed ev;
2247
Johan Hedberg2a611692011-02-19 12:06:00 -03002248 bacpy(&ev.bdaddr, bdaddr);
2249 ev.status = status;
2250
Szymon Janc4e51eae2011-02-25 19:05:48 +01002251 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002252}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002253
2254int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2255{
2256 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002257 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002258 struct mgmt_cp_set_local_name ev;
2259 int err;
2260
2261 memset(&ev, 0, sizeof(ev));
2262 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2263
2264 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2265 if (!cmd)
2266 goto send_event;
2267
2268 if (status) {
2269 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2270 goto failed;
2271 }
2272
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002273 hdev = hci_dev_get(index);
2274 if (hdev) {
2275 hci_dev_lock_bh(hdev);
2276 update_eir(hdev);
2277 hci_dev_unlock_bh(hdev);
2278 hci_dev_put(hdev);
2279 }
2280
Johan Hedbergb312b1612011-03-16 14:29:37 +02002281 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2282 sizeof(ev));
2283 if (err < 0)
2284 goto failed;
2285
2286send_event:
2287 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2288 cmd ? cmd->sk : NULL);
2289
2290failed:
2291 if (cmd)
2292 mgmt_pending_remove(cmd);
2293 return err;
2294}
Szymon Jancc35938b2011-03-22 13:12:21 +01002295
2296int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2297 u8 status)
2298{
2299 struct pending_cmd *cmd;
2300 int err;
2301
2302 BT_DBG("hci%u status %u", index, status);
2303
2304 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2305 if (!cmd)
2306 return -ENOENT;
2307
2308 if (status) {
2309 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2310 EIO);
2311 } else {
2312 struct mgmt_rp_read_local_oob_data rp;
2313
2314 memcpy(rp.hash, hash, sizeof(rp.hash));
2315 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2316
2317 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2318 &rp, sizeof(rp));
2319 }
2320
2321 mgmt_pending_remove(cmd);
2322
2323 return err;
2324}
Johan Hedberge17acd42011-03-30 23:57:16 +03002325
2326int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2327 u8 *eir)
2328{
2329 struct mgmt_ev_device_found ev;
2330
2331 memset(&ev, 0, sizeof(ev));
2332
2333 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002334 ev.rssi = rssi;
2335
2336 if (eir)
2337 memcpy(ev.eir, eir, sizeof(ev.eir));
2338
Andre Guedesf8523592011-09-09 18:56:26 -03002339 if (dev_class)
2340 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2341
Johan Hedberge17acd42011-03-30 23:57:16 +03002342 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2343}
Johan Hedberga88a9652011-03-30 13:18:12 +03002344
2345int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2346{
2347 struct mgmt_ev_remote_name ev;
2348
2349 memset(&ev, 0, sizeof(ev));
2350
2351 bacpy(&ev.bdaddr, bdaddr);
2352 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2353
2354 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2355}
Johan Hedberg314b2382011-04-27 10:29:57 -04002356
Johan Hedberg164a6e72011-11-01 17:06:44 +02002357int mgmt_inquiry_failed(u16 index, u8 status)
2358{
2359 struct pending_cmd *cmd;
2360 int err;
2361
2362 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2363 if (!cmd)
2364 return -ENOENT;
2365
2366 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2367 mgmt_pending_remove(cmd);
2368
2369 return err;
2370}
2371
Johan Hedberg314b2382011-04-27 10:29:57 -04002372int mgmt_discovering(u16 index, u8 discovering)
2373{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002374 struct pending_cmd *cmd;
2375
2376 if (discovering)
2377 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2378 else
2379 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2380
2381 if (cmd != NULL) {
2382 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2383 mgmt_pending_remove(cmd);
2384 }
2385
Johan Hedberg314b2382011-04-27 10:29:57 -04002386 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2387 sizeof(discovering), NULL);
2388}
Antti Julku5e762442011-08-25 16:48:02 +03002389
2390int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2391{
2392 struct pending_cmd *cmd;
2393 struct mgmt_ev_device_blocked ev;
2394
2395 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2396
2397 bacpy(&ev.bdaddr, bdaddr);
2398
2399 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2400 cmd ? cmd->sk : NULL);
2401}
2402
2403int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2404{
2405 struct pending_cmd *cmd;
2406 struct mgmt_ev_device_unblocked ev;
2407
2408 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2409
2410 bacpy(&ev.bdaddr, bdaddr);
2411
2412 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2413 cmd ? cmd->sk : NULL);
2414}