blob: 6f9e3cd0d1fdf20bb4bca080adea35b8362fa064 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
39 __u16 opcode;
40 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
Johannes Bergb5ad8b72011-06-01 08:54:45 +020046static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047
Szymon Janc4e51eae2011-02-25 19:05:48 +010048static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020049{
50 struct sk_buff *skb;
51 struct mgmt_hdr *hdr;
52 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030053 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
Szymon Janc34eb5252011-02-28 14:10:08 +010055 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020056
57 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
58 if (!skb)
59 return -ENOMEM;
60
61 hdr = (void *) skb_put(skb, sizeof(*hdr));
62
63 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010064 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020065 hdr->len = cpu_to_le16(sizeof(*ev));
66
67 ev = (void *) skb_put(skb, sizeof(*ev));
68 ev->status = status;
69 put_unaligned_le16(cmd, &ev->opcode);
70
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030071 err = sock_queue_rcv_skb(sk, skb);
72 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020073 kfree_skb(skb);
74
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030075 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020076}
77
Szymon Janc4e51eae2011-02-25 19:05:48 +010078static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
79 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020080{
81 struct sk_buff *skb;
82 struct mgmt_hdr *hdr;
83 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030084 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020085
86 BT_DBG("sock %p", sk);
87
Johan Hedberga38528f2011-01-22 06:46:43 +020088 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020089 if (!skb)
90 return -ENOMEM;
91
92 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020093
Johan Hedberg02d98122010-12-13 21:07:04 +020094 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010095 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020096 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020097
Johan Hedberga38528f2011-01-22 06:46:43 +020098 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
99 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100100
101 if (rp)
102 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200103
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300104 err = sock_queue_rcv_skb(sk, skb);
105 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200106 kfree_skb(skb);
107
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300108 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200109}
110
Johan Hedberga38528f2011-01-22 06:46:43 +0200111static int read_version(struct sock *sk)
112{
113 struct mgmt_rp_read_version rp;
114
115 BT_DBG("sock %p", sk);
116
117 rp.version = MGMT_VERSION;
118 put_unaligned_le16(MGMT_REVISION, &rp.revision);
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
121 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200122}
123
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124static int read_index_list(struct sock *sk)
125{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200126 struct mgmt_rp_read_index_list *rp;
127 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200128 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200131 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200132
133 BT_DBG("sock %p", sk);
134
135 read_lock(&hci_dev_list_lock);
136
137 count = 0;
138 list_for_each(p, &hci_dev_list) {
139 count++;
140 }
141
Johan Hedberga38528f2011-01-22 06:46:43 +0200142 rp_len = sizeof(*rp) + (2 * count);
143 rp = kmalloc(rp_len, GFP_ATOMIC);
144 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100147 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200148
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200149 put_unaligned_le16(count, &rp->num_controllers);
150
151 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200152 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200153 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
154 cancel_delayed_work_sync(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200155
156 if (test_bit(HCI_SETUP, &d->flags))
157 continue;
158
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200159 put_unaligned_le16(d->id, &rp->index[i++]);
160 BT_DBG("Added hci%u", d->id);
161 }
162
163 read_unlock(&hci_dev_list_lock);
164
Szymon Janc4e51eae2011-02-25 19:05:48 +0100165 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
166 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200167
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 kfree(rp);
169
170 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200171}
172
Szymon Janc4e51eae2011-02-25 19:05:48 +0100173static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200174{
Johan Hedberga38528f2011-01-22 06:46:43 +0200175 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200176 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200177
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200179
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200181 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200183
Johan Hedberg32435532011-11-07 22:16:04 +0200184 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
185 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200186
Andre Guedes8c156c32011-07-07 10:30:36 -0300187 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200188
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200189 set_bit(HCI_MGMT, &hdev->flags);
190
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200191 memset(&rp, 0, sizeof(rp));
192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200194
Johan Hedberga38528f2011-01-22 06:46:43 +0200195 rp.powered = test_bit(HCI_UP, &hdev->flags);
196 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
197 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
198 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199
200 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Johan Hedberga38528f2011-01-22 06:46:43 +0200207 bacpy(&rp.bdaddr, &hdev->bdaddr);
208 memcpy(rp.features, hdev->features, 8);
209 memcpy(rp.dev_class, hdev->dev_class, 3);
210 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
211 rp.hci_ver = hdev->hci_ver;
212 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200214 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
215
Andre Guedes8c156c32011-07-07 10:30:36 -0300216 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200218
Szymon Janc4e51eae2011-02-25 19:05:48 +0100219 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200220}
221
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200222static void mgmt_pending_free(struct pending_cmd *cmd)
223{
224 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100225 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200226 kfree(cmd);
227}
228
Johan Hedberg366a0332011-02-19 12:05:55 -0300229static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
230 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200231{
232 struct pending_cmd *cmd;
233
234 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
235 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300236 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200237
238 cmd->opcode = opcode;
239 cmd->index = index;
240
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100241 cmd->param = kmalloc(len, GFP_ATOMIC);
242 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200243 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300244 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200245 }
246
Szymon Janc8fce6352011-03-22 13:12:20 +0100247 if (data)
248 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200249
250 cmd->sk = sk;
251 sock_hold(sk);
252
253 list_add(&cmd->list, &cmd_list);
254
Johan Hedberg366a0332011-02-19 12:05:55 -0300255 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200256}
257
258static void mgmt_pending_foreach(u16 opcode, int index,
259 void (*cb)(struct pending_cmd *cmd, void *data),
260 void *data)
261{
262 struct list_head *p, *n;
263
264 list_for_each_safe(p, n, &cmd_list) {
265 struct pending_cmd *cmd;
266
267 cmd = list_entry(p, struct pending_cmd, list);
268
Johan Hedbergb24752f2011-11-03 14:40:33 +0200269 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200270 continue;
271
272 if (index >= 0 && cmd->index != index)
273 continue;
274
275 cb(cmd, data);
276 }
277}
278
279static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
280{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200281 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200283 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200284 if (cmd->opcode != opcode)
285 continue;
286
287 if (index >= 0 && cmd->index != index)
288 continue;
289
290 return cmd;
291 }
292
293 return NULL;
294}
295
Johan Hedberga664b5b2011-02-19 12:06:02 -0300296static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200298 list_del(&cmd->list);
299 mgmt_pending_free(cmd);
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200304 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300307 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
309 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Janc4e51eae2011-02-25 19:05:48 +0100311 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100313 if (len != sizeof(*cp))
314 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
315
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100318 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
Andre Guedes8c156c32011-07-07 10:30:36 -0300320 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321
322 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200323 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100324 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200325 goto failed;
326 }
327
Szymon Janc4e51eae2011-02-25 19:05:48 +0100328 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
329 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330 goto failed;
331 }
332
Szymon Janc4e51eae2011-02-25 19:05:48 +0100333 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 if (!cmd) {
335 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300337 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338
Johan Hedberg72a734e2010-12-30 00:38:22 +0200339 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340 queue_work(hdev->workqueue, &hdev->power_on);
341 else
Johan Hedberg32435532011-11-07 22:16:04 +0200342 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
Johan Hedberg366a0332011-02-19 12:05:55 -0300344 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345
346failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300347 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300349 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350}
351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
353 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200355 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 u8 scan;
359 int err;
360
361 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Janc4e51eae2011-02-25 19:05:48 +0100363 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100365 if (len != sizeof(*cp))
366 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
367
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100370 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
Andre Guedes8c156c32011-07-07 10:30:36 -0300372 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373
374 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100375 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 goto failed;
377 }
378
Szymon Janc4e51eae2011-02-25 19:05:48 +0100379 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
380 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
381 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 goto failed;
383 }
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100387 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200388 goto failed;
389 }
390
Szymon Janc4e51eae2011-02-25 19:05:48 +0100391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300392 if (!cmd) {
393 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396
397 scan = SCAN_PAGE;
398
Johan Hedberg72a734e2010-12-30 00:38:22 +0200399 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200400 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200401 else
402 cancel_delayed_work_sync(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403
404 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
405 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300406 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200407
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200408 if (cp->val)
409 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
410
Johan Hedberg73f22f62010-12-29 16:00:25 +0200411failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300412 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200413 hci_dev_put(hdev);
414
415 return err;
416}
417
Szymon Janc4e51eae2011-02-25 19:05:48 +0100418static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
419 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200420{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200421 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300423 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200424 u8 scan;
425 int err;
426
427 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Szymon Janc4e51eae2011-02-25 19:05:48 +0100429 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100431 if (len != sizeof(*cp))
432 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
433
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100436 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437
Andre Guedes8c156c32011-07-07 10:30:36 -0300438 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439
440 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100441 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200442 goto failed;
443 }
444
Szymon Janc4e51eae2011-02-25 19:05:48 +0100445 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
446 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
447 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200448 goto failed;
449 }
450
Johan Hedberg72a734e2010-12-30 00:38:22 +0200451 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100452 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200453 goto failed;
454 }
455
Szymon Janc4e51eae2011-02-25 19:05:48 +0100456 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300457 if (!cmd) {
458 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300460 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
Johan Hedberg72a734e2010-12-30 00:38:22 +0200462 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463 scan = SCAN_PAGE;
464 else
465 scan = 0;
466
467 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
468 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300469 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200470
471failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300472 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200473 hci_dev_put(hdev);
474
475 return err;
476}
477
Szymon Janc4e51eae2011-02-25 19:05:48 +0100478static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
479 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200480{
481 struct sk_buff *skb;
482 struct mgmt_hdr *hdr;
483
484 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
485 if (!skb)
486 return -ENOMEM;
487
488 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
489
490 hdr = (void *) skb_put(skb, sizeof(*hdr));
491 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100492 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200493 hdr->len = cpu_to_le16(data_len);
494
Szymon Janc4e51eae2011-02-25 19:05:48 +0100495 if (data)
496 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200497
498 hci_send_to_sock(NULL, skb, skip_sk);
499 kfree_skb(skb);
500
501 return 0;
502}
503
Johan Hedberg053f0212011-01-26 13:07:10 +0200504static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
505{
Johan Hedberga38528f2011-01-22 06:46:43 +0200506 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200507
Johan Hedberga38528f2011-01-22 06:46:43 +0200508 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200509
Szymon Janc4e51eae2011-02-25 19:05:48 +0100510 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200511}
512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
514 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200515{
516 struct mgmt_mode *cp, ev;
517 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200518 int err;
519
520 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
Szymon Janc4e51eae2011-02-25 19:05:48 +0100522 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100524 if (len != sizeof(*cp))
525 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
526
Szymon Janc4e51eae2011-02-25 19:05:48 +0100527 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100529 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530
Andre Guedes8c156c32011-07-07 10:30:36 -0300531 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532
533 if (cp->val)
534 set_bit(HCI_PAIRABLE, &hdev->flags);
535 else
536 clear_bit(HCI_PAIRABLE, &hdev->flags);
537
Szymon Janc4e51eae2011-02-25 19:05:48 +0100538 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539 if (err < 0)
540 goto failed;
541
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 ev.val = cp->val;
543
Szymon Janc4e51eae2011-02-25 19:05:48 +0100544 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200545
546failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300547 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200548 hci_dev_put(hdev);
549
550 return err;
551}
552
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300553#define EIR_FLAGS 0x01 /* flags */
554#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
555#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
556#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
557#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
558#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
559#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
560#define EIR_NAME_SHORT 0x08 /* shortened local name */
561#define EIR_NAME_COMPLETE 0x09 /* complete local name */
562#define EIR_TX_POWER 0x0A /* transmit power level */
563#define EIR_DEVICE_ID 0x10 /* device ID */
564
565#define PNP_INFO_SVCLASS_ID 0x1200
566
567static u8 bluetooth_base_uuid[] = {
568 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
569 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570};
571
572static u16 get_uuid16(u8 *uuid128)
573{
574 u32 val;
575 int i;
576
577 for (i = 0; i < 12; i++) {
578 if (bluetooth_base_uuid[i] != uuid128[i])
579 return 0;
580 }
581
582 memcpy(&val, &uuid128[12], 4);
583
584 val = le32_to_cpu(val);
585 if (val > 0xffff)
586 return 0;
587
588 return (u16) val;
589}
590
591static void create_eir(struct hci_dev *hdev, u8 *data)
592{
593 u8 *ptr = data;
594 u16 eir_len = 0;
595 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
596 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200597 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598 size_t name_len;
599
600 name_len = strlen(hdev->dev_name);
601
602 if (name_len > 0) {
603 /* EIR Data type */
604 if (name_len > 48) {
605 name_len = 48;
606 ptr[1] = EIR_NAME_SHORT;
607 } else
608 ptr[1] = EIR_NAME_COMPLETE;
609
610 /* EIR Data length */
611 ptr[0] = name_len + 1;
612
613 memcpy(ptr + 2, hdev->dev_name, name_len);
614
615 eir_len += (name_len + 2);
616 ptr += (name_len + 2);
617 }
618
619 memset(uuid16_list, 0, sizeof(uuid16_list));
620
621 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200622 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300623 u16 uuid16;
624
625 uuid16 = get_uuid16(uuid->uuid);
626 if (uuid16 == 0)
627 return;
628
629 if (uuid16 < 0x1100)
630 continue;
631
632 if (uuid16 == PNP_INFO_SVCLASS_ID)
633 continue;
634
635 /* Stop if not enough space to put next UUID */
636 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
637 truncated = 1;
638 break;
639 }
640
641 /* Check for duplicates */
642 for (i = 0; uuid16_list[i] != 0; i++)
643 if (uuid16_list[i] == uuid16)
644 break;
645
646 if (uuid16_list[i] == 0) {
647 uuid16_list[i] = uuid16;
648 eir_len += sizeof(u16);
649 }
650 }
651
652 if (uuid16_list[0] != 0) {
653 u8 *length = ptr;
654
655 /* EIR Data type */
656 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
657
658 ptr += 2;
659 eir_len += 2;
660
661 for (i = 0; uuid16_list[i] != 0; i++) {
662 *ptr++ = (uuid16_list[i] & 0x00ff);
663 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
664 }
665
666 /* EIR Data length */
667 *length = (i * sizeof(u16)) + 1;
668 }
669}
670
671static int update_eir(struct hci_dev *hdev)
672{
673 struct hci_cp_write_eir cp;
674
675 if (!(hdev->features[6] & LMP_EXT_INQ))
676 return 0;
677
678 if (hdev->ssp_mode == 0)
679 return 0;
680
681 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
682 return 0;
683
684 memset(&cp, 0, sizeof(cp));
685
686 create_eir(hdev, cp.data);
687
688 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
689 return 0;
690
691 memcpy(hdev->eir, cp.data, sizeof(cp.data));
692
693 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
694}
695
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696static u8 get_service_classes(struct hci_dev *hdev)
697{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300698 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699 u8 val = 0;
700
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300701 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200703
704 return val;
705}
706
707static int update_class(struct hci_dev *hdev)
708{
709 u8 cod[3];
710
711 BT_DBG("%s", hdev->name);
712
713 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
714 return 0;
715
716 cod[0] = hdev->minor_class;
717 cod[1] = hdev->major_class;
718 cod[2] = get_service_classes(hdev);
719
720 if (memcmp(cod, hdev->dev_class, 3) == 0)
721 return 0;
722
723 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
724}
725
Szymon Janc4e51eae2011-02-25 19:05:48 +0100726static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200727{
728 struct mgmt_cp_add_uuid *cp;
729 struct hci_dev *hdev;
730 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200731 int err;
732
733 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Szymon Janc4e51eae2011-02-25 19:05:48 +0100735 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100737 if (len != sizeof(*cp))
738 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
739
Szymon Janc4e51eae2011-02-25 19:05:48 +0100740 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743
Andre Guedes8c156c32011-07-07 10:30:36 -0300744 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200745
746 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
747 if (!uuid) {
748 err = -ENOMEM;
749 goto failed;
750 }
751
752 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200753 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200754
755 list_add(&uuid->list, &hdev->uuids);
756
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200757 err = update_class(hdev);
758 if (err < 0)
759 goto failed;
760
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300761 err = update_eir(hdev);
762 if (err < 0)
763 goto failed;
764
Szymon Janc4e51eae2011-02-25 19:05:48 +0100765 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200766
767failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300768 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769 hci_dev_put(hdev);
770
771 return err;
772}
773
Szymon Janc4e51eae2011-02-25 19:05:48 +0100774static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200775{
776 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100777 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200778 struct hci_dev *hdev;
779 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 +0200780 int err, found;
781
782 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Szymon Janc4e51eae2011-02-25 19:05:48 +0100784 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100786 if (len != sizeof(*cp))
787 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
788
Szymon Janc4e51eae2011-02-25 19:05:48 +0100789 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100791 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792
Andre Guedes8c156c32011-07-07 10:30:36 -0300793 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
795 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
796 err = hci_uuids_clear(hdev);
797 goto unlock;
798 }
799
800 found = 0;
801
802 list_for_each_safe(p, n, &hdev->uuids) {
803 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
804
805 if (memcmp(match->uuid, cp->uuid, 16) != 0)
806 continue;
807
808 list_del(&match->list);
809 found++;
810 }
811
812 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100813 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200814 goto unlock;
815 }
816
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200817 err = update_class(hdev);
818 if (err < 0)
819 goto unlock;
820
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300821 err = update_eir(hdev);
822 if (err < 0)
823 goto unlock;
824
Szymon Janc4e51eae2011-02-25 19:05:48 +0100825 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200826
827unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300828 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200829 hci_dev_put(hdev);
830
831 return err;
832}
833
Szymon Janc4e51eae2011-02-25 19:05:48 +0100834static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
835 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200836{
837 struct hci_dev *hdev;
838 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200839 int err;
840
841 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Szymon Janc4e51eae2011-02-25 19:05:48 +0100843 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100845 if (len != sizeof(*cp))
846 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
847
Szymon Janc4e51eae2011-02-25 19:05:48 +0100848 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851
Andre Guedes8c156c32011-07-07 10:30:36 -0300852 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200853
854 hdev->major_class = cp->major;
855 hdev->minor_class = cp->minor;
856
857 err = update_class(hdev);
858
859 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100860 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861
Andre Guedes8c156c32011-07-07 10:30:36 -0300862 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200863 hci_dev_put(hdev);
864
865 return err;
866}
867
Szymon Janc4e51eae2011-02-25 19:05:48 +0100868static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
869 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870{
871 struct hci_dev *hdev;
872 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200873 int err;
874
875 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100877 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +0100878 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100879
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
Andre Guedes8c156c32011-07-07 10:30:36 -0300884 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
Szymon Janc4e51eae2011-02-25 19:05:48 +0100886 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887
888 if (cp->enable) {
889 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
890 err = 0;
891 } else {
892 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
893 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300894 if (err == 0)
895 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200896 }
897
898 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100899 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
900 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300901 else
902 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
903
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200904
Andre Guedes8c156c32011-07-07 10:30:36 -0300905 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906 hci_dev_put(hdev);
907
908 return err;
909}
910
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200912{
913 struct hci_dev *hdev;
914 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100915 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300916 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200917
918 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100919
920 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300921 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100922
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200923 key_count = get_unaligned_le16(&cp->key_count);
924
925 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300926 if (expected_len != len) {
927 BT_ERR("load_keys: expected %u bytes, got %u bytes",
928 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300929 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200930 }
931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200933 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200937 key_count);
938
Andre Guedes8c156c32011-07-07 10:30:36 -0300939 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200940
941 hci_link_keys_clear(hdev);
942
943 set_bit(HCI_LINK_KEYS, &hdev->flags);
944
945 if (cp->debug_keys)
946 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
947 else
948 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
949
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300950 for (i = 0; i < key_count; i++) {
951 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200952
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700953 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200954 key->pin_len);
955 }
956
Andre Guedes8c156c32011-07-07 10:30:36 -0300957 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200958 hci_dev_put(hdev);
959
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300960 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200961}
962
Szymon Janc4e51eae2011-02-25 19:05:48 +0100963static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200964{
965 struct hci_dev *hdev;
966 struct mgmt_cp_remove_key *cp;
967 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200968 int err;
969
970 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200971
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100972 if (len != sizeof(*cp))
973 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
974
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200976 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200978
Andre Guedes8c156c32011-07-07 10:30:36 -0300979 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200980
981 err = hci_remove_link_key(hdev, &cp->bdaddr);
982 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100983 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200984 goto unlock;
985 }
986
987 err = 0;
988
989 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
990 goto unlock;
991
992 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
993 if (conn) {
994 struct hci_cp_disconnect dc;
995
996 put_unaligned_le16(conn->handle, &dc.handle);
997 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400998 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200999 }
1000
1001unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001002 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001003 hci_dev_put(hdev);
1004
1005 return err;
1006}
1007
Szymon Janc4e51eae2011-02-25 19:05:48 +01001008static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001009{
1010 struct hci_dev *hdev;
1011 struct mgmt_cp_disconnect *cp;
1012 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001013 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001014 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001015 int err;
1016
1017 BT_DBG("");
1018
1019 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001021 if (len != sizeof(*cp))
1022 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1023
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001026 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001027
Andre Guedes8c156c32011-07-07 10:30:36 -03001028 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001029
1030 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032 goto failed;
1033 }
1034
Szymon Janc4e51eae2011-02-25 19:05:48 +01001035 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1036 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037 goto failed;
1038 }
1039
1040 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001041 if (!conn)
1042 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1043
Johan Hedberg8962ee72011-01-20 12:40:27 +02001044 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046 goto failed;
1047 }
1048
Szymon Janc4e51eae2011-02-25 19:05:48 +01001049 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001050 if (!cmd) {
1051 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001052 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001053 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001054
1055 put_unaligned_le16(conn->handle, &dc.handle);
1056 dc.reason = 0x13; /* Remote User Terminated Connection */
1057
1058 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1059 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001060 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001061
1062failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001063 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064 hci_dev_put(hdev);
1065
1066 return err;
1067}
1068
Szymon Janc8ce62842011-03-01 16:55:32 +01001069static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001070{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001071 struct mgmt_rp_get_connections *rp;
1072 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001073 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001074 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001075 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077 int i, err;
1078
1079 BT_DBG("");
1080
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001082 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001083 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001084
Andre Guedes8c156c32011-07-07 10:30:36 -03001085 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001086
1087 count = 0;
1088 list_for_each(p, &hdev->conn_hash.list) {
1089 count++;
1090 }
1091
Johan Hedberga38528f2011-01-22 06:46:43 +02001092 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1093 rp = kmalloc(rp_len, GFP_ATOMIC);
1094 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001095 err = -ENOMEM;
1096 goto unlock;
1097 }
1098
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099 put_unaligned_le16(count, &rp->conn_count);
1100
Johan Hedberg2784eb42011-01-21 13:56:35 +02001101 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001102 list_for_each_entry(c, &hdev->conn_hash.list, list)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001103 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104
Szymon Janc4e51eae2011-02-25 19:05:48 +01001105 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001106
1107unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001108 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001109 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001110 hci_dev_put(hdev);
1111 return err;
1112}
1113
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001114static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1115 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1116{
1117 struct pending_cmd *cmd;
1118 int err;
1119
1120 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1121 sizeof(*cp));
1122 if (!cmd)
1123 return -ENOMEM;
1124
1125 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1126 &cp->bdaddr);
1127 if (err < 0)
1128 mgmt_pending_remove(cmd);
1129
1130 return err;
1131}
1132
Szymon Janc4e51eae2011-02-25 19:05:48 +01001133static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1134 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001135{
1136 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001137 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001139 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001140 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001141 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001142 int err;
1143
1144 BT_DBG("");
1145
1146 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001147
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001148 if (len != sizeof(*cp))
1149 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1150
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001153 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154
Andre Guedes8c156c32011-07-07 10:30:36 -03001155 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001156
1157 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001158 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001159 goto failed;
1160 }
1161
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001162 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1163 if (!conn) {
1164 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1165 goto failed;
1166 }
1167
1168 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1169 bacpy(&ncp.bdaddr, &cp->bdaddr);
1170
1171 BT_ERR("PIN code is not 16 bytes long");
1172
1173 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1174 if (err >= 0)
1175 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1176 EINVAL);
1177
1178 goto failed;
1179 }
1180
Szymon Janc4e51eae2011-02-25 19:05:48 +01001181 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001182 if (!cmd) {
1183 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001185 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186
1187 bacpy(&reply.bdaddr, &cp->bdaddr);
1188 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001189 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001190
1191 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1192 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001193 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001194
1195failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001196 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001197 hci_dev_put(hdev);
1198
1199 return err;
1200}
1201
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1203 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001204{
1205 struct hci_dev *hdev;
1206 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001207 int err;
1208
1209 BT_DBG("");
1210
1211 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001212
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001213 if (len != sizeof(*cp))
1214 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1215 EINVAL);
1216
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001218 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001219 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1220 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221
Andre Guedes8c156c32011-07-07 10:30:36 -03001222 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001223
1224 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1226 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001227 goto failed;
1228 }
1229
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001230 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001231
1232failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001233 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234 hci_dev_put(hdev);
1235
1236 return err;
1237}
1238
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1240 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001241{
1242 struct hci_dev *hdev;
1243 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001244
1245 BT_DBG("");
1246
1247 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001248
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001249 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001250 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001251
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001254 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255
Andre Guedes8c156c32011-07-07 10:30:36 -03001256 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001257
1258 hdev->io_capability = cp->io_capability;
1259
1260 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001261 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001262
Andre Guedes8c156c32011-07-07 10:30:36 -03001263 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001264 hci_dev_put(hdev);
1265
Szymon Janc4e51eae2011-02-25 19:05:48 +01001266 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001267}
1268
Johan Hedberge9a416b2011-02-19 12:05:56 -03001269static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1270{
1271 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001272 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001273
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001274 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001275 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1276 continue;
1277
1278 if (cmd->index != hdev->id)
1279 continue;
1280
1281 if (cmd->user_data != conn)
1282 continue;
1283
1284 return cmd;
1285 }
1286
1287 return NULL;
1288}
1289
1290static void pairing_complete(struct pending_cmd *cmd, u8 status)
1291{
1292 struct mgmt_rp_pair_device rp;
1293 struct hci_conn *conn = cmd->user_data;
1294
Johan Hedberge9a416b2011-02-19 12:05:56 -03001295 bacpy(&rp.bdaddr, &conn->dst);
1296 rp.status = status;
1297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001299
1300 /* So we don't get further callbacks for this connection */
1301 conn->connect_cfm_cb = NULL;
1302 conn->security_cfm_cb = NULL;
1303 conn->disconn_cfm_cb = NULL;
1304
1305 hci_conn_put(conn);
1306
Johan Hedberga664b5b2011-02-19 12:06:02 -03001307 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001308}
1309
1310static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1311{
1312 struct pending_cmd *cmd;
1313
1314 BT_DBG("status %u", status);
1315
1316 cmd = find_pairing(conn);
1317 if (!cmd) {
1318 BT_DBG("Unable to find a pending command");
1319 return;
1320 }
1321
1322 pairing_complete(cmd, status);
1323}
1324
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001326{
1327 struct hci_dev *hdev;
1328 struct mgmt_cp_pair_device *cp;
1329 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001330 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331 u8 sec_level, auth_type;
1332 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333 int err;
1334
1335 BT_DBG("");
1336
1337 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001339 if (len != sizeof(*cp))
1340 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1341
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345
Andre Guedes8c156c32011-07-07 10:30:36 -03001346 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001348 sec_level = BT_SECURITY_MEDIUM;
1349 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001351 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001353
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001354 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1355 if (entry)
1356 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1357 auth_type);
1358 else
1359 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1360 auth_type);
1361
Ville Tervo30e76272011-02-22 16:10:53 -03001362 if (IS_ERR(conn)) {
1363 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001364 goto unlock;
1365 }
1366
1367 if (conn->connect_cfm_cb) {
1368 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370 goto unlock;
1371 }
1372
Szymon Janc4e51eae2011-02-25 19:05:48 +01001373 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001374 if (!cmd) {
1375 err = -ENOMEM;
1376 hci_conn_put(conn);
1377 goto unlock;
1378 }
1379
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001380 /* For LE, just connecting isn't a proof that the pairing finished */
1381 if (!entry)
1382 conn->connect_cfm_cb = pairing_complete_cb;
1383
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384 conn->security_cfm_cb = pairing_complete_cb;
1385 conn->disconn_cfm_cb = pairing_complete_cb;
1386 conn->io_capability = cp->io_cap;
1387 cmd->user_data = conn;
1388
1389 if (conn->state == BT_CONNECTED &&
1390 hci_conn_security(conn, sec_level, auth_type))
1391 pairing_complete(cmd, 0);
1392
1393 err = 0;
1394
1395unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001396 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001397 hci_dev_put(hdev);
1398
1399 return err;
1400}
1401
Szymon Janc4e51eae2011-02-25 19:05:48 +01001402static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1403 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001404{
1405 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001406 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001407 struct pending_cmd *cmd;
1408 struct hci_dev *hdev;
1409 int err;
1410
1411 BT_DBG("");
1412
Johan Hedberga5c29682011-02-19 12:05:57 -03001413 if (success) {
1414 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1415 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1416 } else {
1417 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1418 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1419 }
1420
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421 if (len != sizeof(*cp))
1422 return cmd_status(sk, index, mgmt_op, EINVAL);
1423
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001425 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001427
Andre Guedes8c156c32011-07-07 10:30:36 -03001428 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001429
Johan Hedberga5c29682011-02-19 12:05:57 -03001430 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001432 goto failed;
1433 }
1434
Szymon Janc4e51eae2011-02-25 19:05:48 +01001435 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001436 if (!cmd) {
1437 err = -ENOMEM;
1438 goto failed;
1439 }
1440
1441 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001442 if (err < 0)
1443 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001444
1445failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001446 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001447 hci_dev_put(hdev);
1448
1449 return err;
1450}
1451
Johan Hedbergb312b1612011-03-16 14:29:37 +02001452static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1453 u16 len)
1454{
1455 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1456 struct hci_cp_write_local_name hci_cp;
1457 struct hci_dev *hdev;
1458 struct pending_cmd *cmd;
1459 int err;
1460
1461 BT_DBG("");
1462
1463 if (len != sizeof(*mgmt_cp))
1464 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1465
1466 hdev = hci_dev_get(index);
1467 if (!hdev)
1468 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1469
Andre Guedes8c156c32011-07-07 10:30:36 -03001470 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001471
1472 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1473 if (!cmd) {
1474 err = -ENOMEM;
1475 goto failed;
1476 }
1477
1478 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1479 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1480 &hci_cp);
1481 if (err < 0)
1482 mgmt_pending_remove(cmd);
1483
1484failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001485 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001486 hci_dev_put(hdev);
1487
1488 return err;
1489}
1490
Szymon Jancc35938b2011-03-22 13:12:21 +01001491static int read_local_oob_data(struct sock *sk, u16 index)
1492{
1493 struct hci_dev *hdev;
1494 struct pending_cmd *cmd;
1495 int err;
1496
1497 BT_DBG("hci%u", index);
1498
1499 hdev = hci_dev_get(index);
1500 if (!hdev)
1501 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1502 ENODEV);
1503
Andre Guedes8c156c32011-07-07 10:30:36 -03001504 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001505
1506 if (!test_bit(HCI_UP, &hdev->flags)) {
1507 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1508 ENETDOWN);
1509 goto unlock;
1510 }
1511
1512 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1513 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1514 EOPNOTSUPP);
1515 goto unlock;
1516 }
1517
1518 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1519 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1520 goto unlock;
1521 }
1522
1523 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1524 if (!cmd) {
1525 err = -ENOMEM;
1526 goto unlock;
1527 }
1528
1529 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1530 if (err < 0)
1531 mgmt_pending_remove(cmd);
1532
1533unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001534 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001535 hci_dev_put(hdev);
1536
1537 return err;
1538}
1539
Szymon Janc2763eda2011-03-22 13:12:22 +01001540static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1541 u16 len)
1542{
1543 struct hci_dev *hdev;
1544 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1545 int err;
1546
1547 BT_DBG("hci%u ", index);
1548
1549 if (len != sizeof(*cp))
1550 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1551 EINVAL);
1552
1553 hdev = hci_dev_get(index);
1554 if (!hdev)
1555 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1556 ENODEV);
1557
Andre Guedes8c156c32011-07-07 10:30:36 -03001558 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001559
1560 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1561 cp->randomizer);
1562 if (err < 0)
1563 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1564 else
1565 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1566 0);
1567
Andre Guedes8c156c32011-07-07 10:30:36 -03001568 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001569 hci_dev_put(hdev);
1570
1571 return err;
1572}
1573
1574static int remove_remote_oob_data(struct sock *sk, u16 index,
1575 unsigned char *data, u16 len)
1576{
1577 struct hci_dev *hdev;
1578 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1579 int err;
1580
1581 BT_DBG("hci%u ", index);
1582
1583 if (len != sizeof(*cp))
1584 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1585 EINVAL);
1586
1587 hdev = hci_dev_get(index);
1588 if (!hdev)
1589 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1590 ENODEV);
1591
Andre Guedes8c156c32011-07-07 10:30:36 -03001592 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001593
1594 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1595 if (err < 0)
1596 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1597 -err);
1598 else
1599 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1600 NULL, 0);
1601
Andre Guedes8c156c32011-07-07 10:30:36 -03001602 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001603 hci_dev_put(hdev);
1604
1605 return err;
1606}
1607
Johan Hedberg14a53662011-04-27 10:29:56 -04001608static int start_discovery(struct sock *sk, u16 index)
1609{
Johan Hedberg14a53662011-04-27 10:29:56 -04001610 struct pending_cmd *cmd;
1611 struct hci_dev *hdev;
1612 int err;
1613
1614 BT_DBG("hci%u", index);
1615
1616 hdev = hci_dev_get(index);
1617 if (!hdev)
1618 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1619
1620 hci_dev_lock_bh(hdev);
1621
1622 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1623 if (!cmd) {
1624 err = -ENOMEM;
1625 goto failed;
1626 }
1627
Andre Guedes2519a1f2011-11-07 11:45:24 -03001628 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001629 if (err < 0)
1630 mgmt_pending_remove(cmd);
1631
1632failed:
1633 hci_dev_unlock_bh(hdev);
1634 hci_dev_put(hdev);
1635
1636 return err;
1637}
1638
1639static int stop_discovery(struct sock *sk, u16 index)
1640{
1641 struct hci_dev *hdev;
1642 struct pending_cmd *cmd;
1643 int err;
1644
1645 BT_DBG("hci%u", index);
1646
1647 hdev = hci_dev_get(index);
1648 if (!hdev)
1649 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1650
1651 hci_dev_lock_bh(hdev);
1652
1653 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1654 if (!cmd) {
1655 err = -ENOMEM;
1656 goto failed;
1657 }
1658
Andre Guedes023d5042011-11-04 14:16:52 -03001659 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001660 if (err < 0)
1661 mgmt_pending_remove(cmd);
1662
1663failed:
1664 hci_dev_unlock_bh(hdev);
1665 hci_dev_put(hdev);
1666
1667 return err;
1668}
1669
Antti Julku7fbec222011-06-15 12:01:15 +03001670static int block_device(struct sock *sk, u16 index, unsigned char *data,
1671 u16 len)
1672{
1673 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001674 struct pending_cmd *cmd;
1675 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001676 int err;
1677
1678 BT_DBG("hci%u", index);
1679
Antti Julku7fbec222011-06-15 12:01:15 +03001680 if (len != sizeof(*cp))
1681 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1682 EINVAL);
1683
1684 hdev = hci_dev_get(index);
1685 if (!hdev)
1686 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1687 ENODEV);
1688
Antti Julku5e762442011-08-25 16:48:02 +03001689 hci_dev_lock_bh(hdev);
1690
1691 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1692 if (!cmd) {
1693 err = -ENOMEM;
1694 goto failed;
1695 }
1696
Antti Julku7fbec222011-06-15 12:01:15 +03001697 err = hci_blacklist_add(hdev, &cp->bdaddr);
1698
1699 if (err < 0)
1700 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1701 else
1702 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1703 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001704
1705 mgmt_pending_remove(cmd);
1706
1707failed:
1708 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001709 hci_dev_put(hdev);
1710
1711 return err;
1712}
1713
1714static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1715 u16 len)
1716{
1717 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001718 struct pending_cmd *cmd;
1719 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001720 int err;
1721
1722 BT_DBG("hci%u", index);
1723
Antti Julku7fbec222011-06-15 12:01:15 +03001724 if (len != sizeof(*cp))
1725 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1726 EINVAL);
1727
1728 hdev = hci_dev_get(index);
1729 if (!hdev)
1730 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1731 ENODEV);
1732
Antti Julku5e762442011-08-25 16:48:02 +03001733 hci_dev_lock_bh(hdev);
1734
1735 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1736 if (!cmd) {
1737 err = -ENOMEM;
1738 goto failed;
1739 }
1740
Antti Julku7fbec222011-06-15 12:01:15 +03001741 err = hci_blacklist_del(hdev, &cp->bdaddr);
1742
1743 if (err < 0)
1744 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1745 else
1746 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1747 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001748
1749 mgmt_pending_remove(cmd);
1750
1751failed:
1752 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001753 hci_dev_put(hdev);
1754
1755 return err;
1756}
1757
Antti Julkuf6422ec2011-06-22 13:11:56 +03001758static int set_fast_connectable(struct sock *sk, u16 index,
1759 unsigned char *data, u16 len)
1760{
1761 struct hci_dev *hdev;
1762 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1763 struct hci_cp_write_page_scan_activity acp;
1764 u8 type;
1765 int err;
1766
1767 BT_DBG("hci%u", index);
1768
1769 if (len != sizeof(*cp))
1770 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1771 EINVAL);
1772
1773 hdev = hci_dev_get(index);
1774 if (!hdev)
1775 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1776 ENODEV);
1777
1778 hci_dev_lock(hdev);
1779
1780 if (cp->enable) {
1781 type = PAGE_SCAN_TYPE_INTERLACED;
1782 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1783 } else {
1784 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1785 acp.interval = 0x0800; /* default 1.28 sec page scan */
1786 }
1787
1788 acp.window = 0x0012; /* default 11.25 msec page scan window */
1789
1790 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1791 sizeof(acp), &acp);
1792 if (err < 0) {
1793 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1794 -err);
1795 goto done;
1796 }
1797
1798 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1799 if (err < 0) {
1800 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1801 -err);
1802 goto done;
1803 }
1804
1805 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1806 NULL, 0);
1807done:
1808 hci_dev_unlock(hdev);
1809 hci_dev_put(hdev);
1810
1811 return err;
1812}
1813
Johan Hedberg03811012010-12-08 00:21:06 +02001814int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1815{
1816 unsigned char *buf;
1817 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001818 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001819 int err;
1820
1821 BT_DBG("got %zu bytes", msglen);
1822
1823 if (msglen < sizeof(*hdr))
1824 return -EINVAL;
1825
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001826 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001827 if (!buf)
1828 return -ENOMEM;
1829
1830 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1831 err = -EFAULT;
1832 goto done;
1833 }
1834
1835 hdr = (struct mgmt_hdr *) buf;
1836 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001837 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001838 len = get_unaligned_le16(&hdr->len);
1839
1840 if (len != msglen - sizeof(*hdr)) {
1841 err = -EINVAL;
1842 goto done;
1843 }
1844
1845 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001846 case MGMT_OP_READ_VERSION:
1847 err = read_version(sk);
1848 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001849 case MGMT_OP_READ_INDEX_LIST:
1850 err = read_index_list(sk);
1851 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001852 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001853 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001854 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001855 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001856 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001857 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001858 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001859 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001860 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001861 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001863 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001864 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001866 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001867 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001869 break;
1870 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001872 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001873 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001875 break;
1876 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001878 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001879 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001881 break;
1882 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001884 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001885 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001887 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001888 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001889 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001890 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001891 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001893 break;
1894 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001896 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001897 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001899 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001903 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001905 break;
1906 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001908 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001909 case MGMT_OP_SET_LOCAL_NAME:
1910 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1911 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001912 case MGMT_OP_READ_LOCAL_OOB_DATA:
1913 err = read_local_oob_data(sk, index);
1914 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001915 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1916 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1917 break;
1918 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1919 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1920 len);
1921 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001922 case MGMT_OP_START_DISCOVERY:
1923 err = start_discovery(sk, index);
1924 break;
1925 case MGMT_OP_STOP_DISCOVERY:
1926 err = stop_discovery(sk, index);
1927 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001928 case MGMT_OP_BLOCK_DEVICE:
1929 err = block_device(sk, index, buf + sizeof(*hdr), len);
1930 break;
1931 case MGMT_OP_UNBLOCK_DEVICE:
1932 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1933 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001934 case MGMT_OP_SET_FAST_CONNECTABLE:
1935 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1936 len);
1937 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001938 default:
1939 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001940 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001941 break;
1942 }
1943
Johan Hedberge41d8b42010-12-13 21:07:03 +02001944 if (err < 0)
1945 goto done;
1946
Johan Hedberg03811012010-12-08 00:21:06 +02001947 err = msglen;
1948
1949done:
1950 kfree(buf);
1951 return err;
1952}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001953
Johan Hedbergb24752f2011-11-03 14:40:33 +02001954static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1955{
1956 u8 *status = data;
1957
1958 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1959 mgmt_pending_remove(cmd);
1960}
1961
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001962int mgmt_index_added(u16 index)
1963{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001964 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001965}
1966
1967int mgmt_index_removed(u16 index)
1968{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001969 u8 status = ENODEV;
1970
1971 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1972
Szymon Janc4e51eae2011-02-25 19:05:48 +01001973 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001974}
1975
Johan Hedberg73f22f62010-12-29 16:00:25 +02001976struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001977 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978 struct sock *sk;
1979};
1980
Johan Hedberg72a734e2010-12-30 00:38:22 +02001981static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001983 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001984 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985
Johan Hedberg72a734e2010-12-30 00:38:22 +02001986 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001987 return;
1988
Johan Hedberg053f0212011-01-26 13:07:10 +02001989 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001990
1991 list_del(&cmd->list);
1992
1993 if (match->sk == NULL) {
1994 match->sk = cmd->sk;
1995 sock_hold(match->sk);
1996 }
1997
1998 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001999}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002000
2001int mgmt_powered(u16 index, u8 powered)
2002{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002003 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002004 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002006
Johan Hedberg72a734e2010-12-30 00:38:22 +02002007 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002008
Johan Hedbergb24752f2011-11-03 14:40:33 +02002009 if (!powered) {
2010 u8 status = ENETDOWN;
2011 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2012 }
2013
Johan Hedberg72a734e2010-12-30 00:38:22 +02002014 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015
Szymon Janc4e51eae2011-02-25 19:05:48 +01002016 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002017
2018 if (match.sk)
2019 sock_put(match.sk);
2020
2021 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002022}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002023
Johan Hedberg73f22f62010-12-29 16:00:25 +02002024int mgmt_discoverable(u16 index, u8 discoverable)
2025{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002026 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002027 struct cmd_lookup match = { discoverable, NULL };
2028 int ret;
2029
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002030 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002031
Johan Hedberg72a734e2010-12-30 00:38:22 +02002032 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002033
Szymon Janc4e51eae2011-02-25 19:05:48 +01002034 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2035 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002036
2037 if (match.sk)
2038 sock_put(match.sk);
2039
2040 return ret;
2041}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002042
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002043int mgmt_connectable(u16 index, u8 connectable)
2044{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002045 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002046 struct cmd_lookup match = { connectable, NULL };
2047 int ret;
2048
Johan Hedberg72a734e2010-12-30 00:38:22 +02002049 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002050
Johan Hedberg72a734e2010-12-30 00:38:22 +02002051 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052
Szymon Janc4e51eae2011-02-25 19:05:48 +01002053 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002054
2055 if (match.sk)
2056 sock_put(match.sk);
2057
2058 return ret;
2059}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002060
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002061int mgmt_write_scan_failed(u16 index, u8 scan, u8 status)
2062{
2063 if (scan & SCAN_PAGE)
2064 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index,
2065 cmd_status_rsp, &status);
2066
2067 if (scan & SCAN_INQUIRY)
2068 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
2069 cmd_status_rsp, &status);
2070
2071 return 0;
2072}
2073
Johan Hedberg4df378a2011-04-28 11:29:03 -07002074int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002075{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002076 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002077
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002078 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002079
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002080 ev.store_hint = persistent;
2081 bacpy(&ev.key.bdaddr, &key->bdaddr);
2082 ev.key.type = key->type;
2083 memcpy(ev.key.val, key->val, 16);
2084 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002085
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002086 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002087}
Johan Hedbergf7520542011-01-20 12:34:39 +02002088
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002089int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002090{
2091 struct mgmt_ev_connected ev;
2092
Johan Hedbergf7520542011-01-20 12:34:39 +02002093 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002094 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002095
Szymon Janc4e51eae2011-02-25 19:05:48 +01002096 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002097}
2098
Johan Hedberg8962ee72011-01-20 12:40:27 +02002099static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2100{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002101 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002102 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002103 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002104
Johan Hedberga38528f2011-01-22 06:46:43 +02002105 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002106
Szymon Janc4e51eae2011-02-25 19:05:48 +01002107 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002108
2109 *sk = cmd->sk;
2110 sock_hold(*sk);
2111
Johan Hedberga664b5b2011-02-19 12:06:02 -03002112 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113}
2114
Johan Hedbergf7520542011-01-20 12:34:39 +02002115int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2116{
2117 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002118 struct sock *sk = NULL;
2119 int err;
2120
2121 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002122
Johan Hedbergf7520542011-01-20 12:34:39 +02002123 bacpy(&ev.bdaddr, bdaddr);
2124
Szymon Janc4e51eae2011-02-25 19:05:48 +01002125 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002126
2127 if (sk)
2128 sock_put(sk);
2129
2130 return err;
2131}
2132
2133int mgmt_disconnect_failed(u16 index)
2134{
2135 struct pending_cmd *cmd;
2136 int err;
2137
2138 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2139 if (!cmd)
2140 return -ENOENT;
2141
Szymon Janc4e51eae2011-02-25 19:05:48 +01002142 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002143
Johan Hedberga664b5b2011-02-19 12:06:02 -03002144 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002145
2146 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002147}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002148
2149int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2150{
2151 struct mgmt_ev_connect_failed ev;
2152
Johan Hedberg17d5c042011-01-22 06:09:08 +02002153 bacpy(&ev.bdaddr, bdaddr);
2154 ev.status = status;
2155
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002157}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002158
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002159int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002160{
2161 struct mgmt_ev_pin_code_request ev;
2162
Johan Hedberg980e1a52011-01-22 06:10:07 +02002163 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002164 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002165
Szymon Janc4e51eae2011-02-25 19:05:48 +01002166 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2167 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002168}
2169
2170int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2171{
2172 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002173 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174 int err;
2175
2176 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2177 if (!cmd)
2178 return -ENOENT;
2179
Johan Hedbergac56fb12011-02-19 12:05:59 -03002180 bacpy(&rp.bdaddr, bdaddr);
2181 rp.status = status;
2182
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2184 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
Johan Hedberga664b5b2011-02-19 12:06:02 -03002186 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002187
2188 return err;
2189}
2190
2191int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2192{
2193 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002194 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002195 int err;
2196
2197 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2198 if (!cmd)
2199 return -ENOENT;
2200
Johan Hedbergac56fb12011-02-19 12:05:59 -03002201 bacpy(&rp.bdaddr, bdaddr);
2202 rp.status = status;
2203
Szymon Janc4e51eae2011-02-25 19:05:48 +01002204 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2205 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002206
Johan Hedberga664b5b2011-02-19 12:06:02 -03002207 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002208
2209 return err;
2210}
Johan Hedberga5c29682011-02-19 12:05:57 -03002211
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002212int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2213 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002214{
2215 struct mgmt_ev_user_confirm_request ev;
2216
2217 BT_DBG("hci%u", index);
2218
Johan Hedberga5c29682011-02-19 12:05:57 -03002219 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002220 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002221 put_unaligned_le32(value, &ev.value);
2222
Szymon Janc4e51eae2011-02-25 19:05:48 +01002223 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2224 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002225}
2226
2227static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2228 u8 opcode)
2229{
2230 struct pending_cmd *cmd;
2231 struct mgmt_rp_user_confirm_reply rp;
2232 int err;
2233
2234 cmd = mgmt_pending_find(opcode, index);
2235 if (!cmd)
2236 return -ENOENT;
2237
Johan Hedberga5c29682011-02-19 12:05:57 -03002238 bacpy(&rp.bdaddr, bdaddr);
2239 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002240 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002241
Johan Hedberga664b5b2011-02-19 12:06:02 -03002242 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002243
2244 return err;
2245}
2246
2247int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2248{
2249 return confirm_reply_complete(index, bdaddr, status,
2250 MGMT_OP_USER_CONFIRM_REPLY);
2251}
2252
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002253int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002254{
2255 return confirm_reply_complete(index, bdaddr, status,
2256 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2257}
Johan Hedberg2a611692011-02-19 12:06:00 -03002258
2259int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2260{
2261 struct mgmt_ev_auth_failed ev;
2262
Johan Hedberg2a611692011-02-19 12:06:00 -03002263 bacpy(&ev.bdaddr, bdaddr);
2264 ev.status = status;
2265
Szymon Janc4e51eae2011-02-25 19:05:48 +01002266 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002267}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002268
2269int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2270{
2271 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002272 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002273 struct mgmt_cp_set_local_name ev;
2274 int err;
2275
2276 memset(&ev, 0, sizeof(ev));
2277 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2278
2279 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2280 if (!cmd)
2281 goto send_event;
2282
2283 if (status) {
2284 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2285 goto failed;
2286 }
2287
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002288 hdev = hci_dev_get(index);
2289 if (hdev) {
2290 hci_dev_lock_bh(hdev);
2291 update_eir(hdev);
2292 hci_dev_unlock_bh(hdev);
2293 hci_dev_put(hdev);
2294 }
2295
Johan Hedbergb312b1612011-03-16 14:29:37 +02002296 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2297 sizeof(ev));
2298 if (err < 0)
2299 goto failed;
2300
2301send_event:
2302 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2303 cmd ? cmd->sk : NULL);
2304
2305failed:
2306 if (cmd)
2307 mgmt_pending_remove(cmd);
2308 return err;
2309}
Szymon Jancc35938b2011-03-22 13:12:21 +01002310
2311int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2312 u8 status)
2313{
2314 struct pending_cmd *cmd;
2315 int err;
2316
2317 BT_DBG("hci%u status %u", index, status);
2318
2319 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2320 if (!cmd)
2321 return -ENOENT;
2322
2323 if (status) {
2324 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2325 EIO);
2326 } else {
2327 struct mgmt_rp_read_local_oob_data rp;
2328
2329 memcpy(rp.hash, hash, sizeof(rp.hash));
2330 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2331
2332 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2333 &rp, sizeof(rp));
2334 }
2335
2336 mgmt_pending_remove(cmd);
2337
2338 return err;
2339}
Johan Hedberge17acd42011-03-30 23:57:16 +03002340
2341int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2342 u8 *eir)
2343{
2344 struct mgmt_ev_device_found ev;
2345
2346 memset(&ev, 0, sizeof(ev));
2347
2348 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002349 ev.rssi = rssi;
2350
2351 if (eir)
2352 memcpy(ev.eir, eir, sizeof(ev.eir));
2353
Andre Guedesf8523592011-09-09 18:56:26 -03002354 if (dev_class)
2355 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2356
Johan Hedberge17acd42011-03-30 23:57:16 +03002357 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2358}
Johan Hedberga88a9652011-03-30 13:18:12 +03002359
2360int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2361{
2362 struct mgmt_ev_remote_name ev;
2363
2364 memset(&ev, 0, sizeof(ev));
2365
2366 bacpy(&ev.bdaddr, bdaddr);
2367 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2368
2369 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2370}
Johan Hedberg314b2382011-04-27 10:29:57 -04002371
Johan Hedberg164a6e72011-11-01 17:06:44 +02002372int mgmt_inquiry_failed(u16 index, u8 status)
2373{
2374 struct pending_cmd *cmd;
2375 int err;
2376
2377 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2378 if (!cmd)
2379 return -ENOENT;
2380
2381 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2382 mgmt_pending_remove(cmd);
2383
2384 return err;
2385}
2386
Johan Hedberg314b2382011-04-27 10:29:57 -04002387int mgmt_discovering(u16 index, u8 discovering)
2388{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002389 struct pending_cmd *cmd;
2390
2391 if (discovering)
2392 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2393 else
2394 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2395
2396 if (cmd != NULL) {
2397 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2398 mgmt_pending_remove(cmd);
2399 }
2400
Johan Hedberg314b2382011-04-27 10:29:57 -04002401 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2402 sizeof(discovering), NULL);
2403}
Antti Julku5e762442011-08-25 16:48:02 +03002404
2405int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2406{
2407 struct pending_cmd *cmd;
2408 struct mgmt_ev_device_blocked ev;
2409
2410 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2411
2412 bacpy(&ev.bdaddr, bdaddr);
2413
2414 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2415 cmd ? cmd->sk : NULL);
2416}
2417
2418int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2419{
2420 struct pending_cmd *cmd;
2421 struct mgmt_ev_device_unblocked ev;
2422
2423 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2424
2425 bacpy(&ev.bdaddr, bdaddr);
2426
2427 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2428 cmd ? cmd->sk : NULL);
2429}