blob: 1939053c3fcd8e2f6c81c90fb7ab6cbe3ffe4304 [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 Jancb8534e02011-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
Johan Hedberg86742e12011-11-07 23:13:38 +0200911static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
912 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200913{
914 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200915 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100916 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300917 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200918
919 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100920
921 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200922 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100923
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200924 key_count = get_unaligned_le16(&cp->key_count);
925
Johan Hedberg86742e12011-11-07 23:13:38 +0200926 expected_len = sizeof(*cp) + key_count *
927 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300928 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200929 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300930 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200931 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200932 }
933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200935 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200936 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200937
Szymon Janc4e51eae2011-02-25 19:05:48 +0100938 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200939 key_count);
940
Andre Guedes8c156c32011-07-07 10:30:36 -0300941 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200942
943 hci_link_keys_clear(hdev);
944
945 set_bit(HCI_LINK_KEYS, &hdev->flags);
946
947 if (cp->debug_keys)
948 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
949 else
950 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
951
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300952 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200953 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200954
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700955 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200956 key->pin_len);
957 }
958
Andre Guedes8c156c32011-07-07 10:30:36 -0300959 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200960 hci_dev_put(hdev);
961
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300962 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200963}
964
Johan Hedberg86742e12011-11-07 23:13:38 +0200965static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
966 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200967{
968 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200969 struct mgmt_cp_remove_keys *cp;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200970 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200971 int err;
972
973 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200974
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100975 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200976 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100977
Szymon Janc4e51eae2011-02-25 19:05:48 +0100978 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200979 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200980 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200981
Andre Guedes8c156c32011-07-07 10:30:36 -0300982 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200983
984 err = hci_remove_link_key(hdev, &cp->bdaddr);
985 if (err < 0) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200986 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200987 goto unlock;
988 }
989
990 err = 0;
991
992 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
993 goto unlock;
994
995 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
996 if (conn) {
997 struct hci_cp_disconnect dc;
998
999 put_unaligned_le16(conn->handle, &dc.handle);
1000 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -04001001 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001002 }
1003
1004unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001005 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Szymon Janc4e51eae2011-02-25 19:05:48 +01001011static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001012{
1013 struct hci_dev *hdev;
1014 struct mgmt_cp_disconnect *cp;
1015 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001016 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001017 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001018 int err;
1019
1020 BT_DBG("");
1021
1022 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001024 if (len != sizeof(*cp))
1025 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1026
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001030
Andre Guedes8c156c32011-07-07 10:30:36 -03001031 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032
1033 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001035 goto failed;
1036 }
1037
Szymon Janc4e51eae2011-02-25 19:05:48 +01001038 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1039 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001040 goto failed;
1041 }
1042
1043 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001044 if (!conn)
1045 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1046
Johan Hedberg8962ee72011-01-20 12:40:27 +02001047 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001048 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 goto failed;
1050 }
1051
Szymon Janc4e51eae2011-02-25 19:05:48 +01001052 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001053 if (!cmd) {
1054 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001055 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001056 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057
1058 put_unaligned_le16(conn->handle, &dc.handle);
1059 dc.reason = 0x13; /* Remote User Terminated Connection */
1060
1061 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1062 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001063 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001064
1065failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001066 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001067 hci_dev_put(hdev);
1068
1069 return err;
1070}
1071
Szymon Janc8ce62842011-03-01 16:55:32 +01001072static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001073{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001074 struct mgmt_rp_get_connections *rp;
1075 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001076 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001078 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001080 int i, err;
1081
1082 BT_DBG("");
1083
Szymon Janc4e51eae2011-02-25 19:05:48 +01001084 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001085 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001086 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001087
Andre Guedes8c156c32011-07-07 10:30:36 -03001088 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001089
1090 count = 0;
1091 list_for_each(p, &hdev->conn_hash.list) {
1092 count++;
1093 }
1094
Johan Hedberga38528f2011-01-22 06:46:43 +02001095 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1096 rp = kmalloc(rp_len, GFP_ATOMIC);
1097 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001098 err = -ENOMEM;
1099 goto unlock;
1100 }
1101
Johan Hedberg2784eb42011-01-21 13:56:35 +02001102 put_unaligned_le16(count, &rp->conn_count);
1103
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001105 list_for_each_entry(c, &hdev->conn_hash.list, list)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001106 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107
Szymon Janc4e51eae2011-02-25 19:05:48 +01001108 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001109
1110unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001111 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001112 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001113 hci_dev_put(hdev);
1114 return err;
1115}
1116
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001117static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1118 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1119{
1120 struct pending_cmd *cmd;
1121 int err;
1122
1123 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1124 sizeof(*cp));
1125 if (!cmd)
1126 return -ENOMEM;
1127
1128 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1129 &cp->bdaddr);
1130 if (err < 0)
1131 mgmt_pending_remove(cmd);
1132
1133 return err;
1134}
1135
Szymon Janc4e51eae2011-02-25 19:05:48 +01001136static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1137 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138{
1139 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001140 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001141 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001142 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001143 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001144 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145 int err;
1146
1147 BT_DBG("");
1148
1149 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001151 if (len != sizeof(*cp))
1152 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001155 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001157
Andre Guedes8c156c32011-07-07 10:30:36 -03001158 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001159
1160 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001161 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001162 goto failed;
1163 }
1164
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001165 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1166 if (!conn) {
1167 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1168 goto failed;
1169 }
1170
1171 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1172 bacpy(&ncp.bdaddr, &cp->bdaddr);
1173
1174 BT_ERR("PIN code is not 16 bytes long");
1175
1176 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1177 if (err >= 0)
1178 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1179 EINVAL);
1180
1181 goto failed;
1182 }
1183
Szymon Janc4e51eae2011-02-25 19:05:48 +01001184 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001185 if (!cmd) {
1186 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001187 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001188 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001189
1190 bacpy(&reply.bdaddr, &cp->bdaddr);
1191 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001192 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001193
1194 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1195 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001196 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001197
1198failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001199 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200 hci_dev_put(hdev);
1201
1202 return err;
1203}
1204
Szymon Janc4e51eae2011-02-25 19:05:48 +01001205static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1206 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001207{
1208 struct hci_dev *hdev;
1209 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210 int err;
1211
1212 BT_DBG("");
1213
1214 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001216 if (len != sizeof(*cp))
1217 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1218 EINVAL);
1219
Szymon Janc4e51eae2011-02-25 19:05:48 +01001220 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001222 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1223 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224
Andre Guedes8c156c32011-07-07 10:30:36 -03001225 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001226
1227 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001228 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1229 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 goto failed;
1231 }
1232
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001233 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234
1235failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001236 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001237 hci_dev_put(hdev);
1238
1239 return err;
1240}
1241
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1243 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001244{
1245 struct hci_dev *hdev;
1246 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001247
1248 BT_DBG("");
1249
1250 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001251
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001252 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001253 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001254
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001256 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001257 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001258
Andre Guedes8c156c32011-07-07 10:30:36 -03001259 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260
1261 hdev->io_capability = cp->io_capability;
1262
1263 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001264 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265
Andre Guedes8c156c32011-07-07 10:30:36 -03001266 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001267 hci_dev_put(hdev);
1268
Szymon Janc4e51eae2011-02-25 19:05:48 +01001269 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001270}
1271
Johan Hedberge9a416b2011-02-19 12:05:56 -03001272static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1273{
1274 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001275 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001276
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001277 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001278 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1279 continue;
1280
1281 if (cmd->index != hdev->id)
1282 continue;
1283
1284 if (cmd->user_data != conn)
1285 continue;
1286
1287 return cmd;
1288 }
1289
1290 return NULL;
1291}
1292
1293static void pairing_complete(struct pending_cmd *cmd, u8 status)
1294{
1295 struct mgmt_rp_pair_device rp;
1296 struct hci_conn *conn = cmd->user_data;
1297
Johan Hedberge9a416b2011-02-19 12:05:56 -03001298 bacpy(&rp.bdaddr, &conn->dst);
1299 rp.status = status;
1300
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001302
1303 /* So we don't get further callbacks for this connection */
1304 conn->connect_cfm_cb = NULL;
1305 conn->security_cfm_cb = NULL;
1306 conn->disconn_cfm_cb = NULL;
1307
1308 hci_conn_put(conn);
1309
Johan Hedberga664b5b2011-02-19 12:06:02 -03001310 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001311}
1312
1313static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1314{
1315 struct pending_cmd *cmd;
1316
1317 BT_DBG("status %u", status);
1318
1319 cmd = find_pairing(conn);
1320 if (!cmd) {
1321 BT_DBG("Unable to find a pending command");
1322 return;
1323 }
1324
1325 pairing_complete(cmd, status);
1326}
1327
Szymon Janc4e51eae2011-02-25 19:05:48 +01001328static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001329{
1330 struct hci_dev *hdev;
1331 struct mgmt_cp_pair_device *cp;
1332 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001333 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001334 u8 sec_level, auth_type;
1335 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336 int err;
1337
1338 BT_DBG("");
1339
1340 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001341
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001342 if (len != sizeof(*cp))
1343 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1344
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001346 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001347 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001348
Andre Guedes8c156c32011-07-07 10:30:36 -03001349 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001351 sec_level = BT_SECURITY_MEDIUM;
1352 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001353 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001354 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001356
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001357 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1358 if (entry)
1359 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1360 auth_type);
1361 else
1362 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1363 auth_type);
1364
Ville Tervo30e76272011-02-22 16:10:53 -03001365 if (IS_ERR(conn)) {
1366 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001367 goto unlock;
1368 }
1369
1370 if (conn->connect_cfm_cb) {
1371 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001372 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373 goto unlock;
1374 }
1375
Szymon Janc4e51eae2011-02-25 19:05:48 +01001376 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377 if (!cmd) {
1378 err = -ENOMEM;
1379 hci_conn_put(conn);
1380 goto unlock;
1381 }
1382
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001383 /* For LE, just connecting isn't a proof that the pairing finished */
1384 if (!entry)
1385 conn->connect_cfm_cb = pairing_complete_cb;
1386
Johan Hedberge9a416b2011-02-19 12:05:56 -03001387 conn->security_cfm_cb = pairing_complete_cb;
1388 conn->disconn_cfm_cb = pairing_complete_cb;
1389 conn->io_capability = cp->io_cap;
1390 cmd->user_data = conn;
1391
1392 if (conn->state == BT_CONNECTED &&
1393 hci_conn_security(conn, sec_level, auth_type))
1394 pairing_complete(cmd, 0);
1395
1396 err = 0;
1397
1398unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001399 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001400 hci_dev_put(hdev);
1401
1402 return err;
1403}
1404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1406 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001407{
1408 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001409 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001410 struct pending_cmd *cmd;
1411 struct hci_dev *hdev;
1412 int err;
1413
1414 BT_DBG("");
1415
Johan Hedberga5c29682011-02-19 12:05:57 -03001416 if (success) {
1417 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1418 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1419 } else {
1420 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1421 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1422 }
1423
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001424 if (len != sizeof(*cp))
1425 return cmd_status(sk, index, mgmt_op, EINVAL);
1426
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001428 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001430
Andre Guedes8c156c32011-07-07 10:30:36 -03001431 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001432
Johan Hedberga5c29682011-02-19 12:05:57 -03001433 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001435 goto failed;
1436 }
1437
Szymon Janc4e51eae2011-02-25 19:05:48 +01001438 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001439 if (!cmd) {
1440 err = -ENOMEM;
1441 goto failed;
1442 }
1443
1444 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001445 if (err < 0)
1446 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001447
1448failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001449 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001450 hci_dev_put(hdev);
1451
1452 return err;
1453}
1454
Johan Hedbergb312b1612011-03-16 14:29:37 +02001455static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1456 u16 len)
1457{
1458 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1459 struct hci_cp_write_local_name hci_cp;
1460 struct hci_dev *hdev;
1461 struct pending_cmd *cmd;
1462 int err;
1463
1464 BT_DBG("");
1465
1466 if (len != sizeof(*mgmt_cp))
1467 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1468
1469 hdev = hci_dev_get(index);
1470 if (!hdev)
1471 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1472
Andre Guedes8c156c32011-07-07 10:30:36 -03001473 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001474
1475 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1476 if (!cmd) {
1477 err = -ENOMEM;
1478 goto failed;
1479 }
1480
1481 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1482 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1483 &hci_cp);
1484 if (err < 0)
1485 mgmt_pending_remove(cmd);
1486
1487failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001488 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001489 hci_dev_put(hdev);
1490
1491 return err;
1492}
1493
Szymon Jancc35938b2011-03-22 13:12:21 +01001494static int read_local_oob_data(struct sock *sk, u16 index)
1495{
1496 struct hci_dev *hdev;
1497 struct pending_cmd *cmd;
1498 int err;
1499
1500 BT_DBG("hci%u", index);
1501
1502 hdev = hci_dev_get(index);
1503 if (!hdev)
1504 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1505 ENODEV);
1506
Andre Guedes8c156c32011-07-07 10:30:36 -03001507 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001508
1509 if (!test_bit(HCI_UP, &hdev->flags)) {
1510 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1511 ENETDOWN);
1512 goto unlock;
1513 }
1514
1515 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1516 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1517 EOPNOTSUPP);
1518 goto unlock;
1519 }
1520
1521 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1522 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1523 goto unlock;
1524 }
1525
1526 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1527 if (!cmd) {
1528 err = -ENOMEM;
1529 goto unlock;
1530 }
1531
1532 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1533 if (err < 0)
1534 mgmt_pending_remove(cmd);
1535
1536unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001537 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001538 hci_dev_put(hdev);
1539
1540 return err;
1541}
1542
Szymon Janc2763eda2011-03-22 13:12:22 +01001543static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1544 u16 len)
1545{
1546 struct hci_dev *hdev;
1547 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1548 int err;
1549
1550 BT_DBG("hci%u ", index);
1551
1552 if (len != sizeof(*cp))
1553 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1554 EINVAL);
1555
1556 hdev = hci_dev_get(index);
1557 if (!hdev)
1558 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1559 ENODEV);
1560
Andre Guedes8c156c32011-07-07 10:30:36 -03001561 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001562
1563 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1564 cp->randomizer);
1565 if (err < 0)
1566 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1567 else
1568 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1569 0);
1570
Andre Guedes8c156c32011-07-07 10:30:36 -03001571 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001572 hci_dev_put(hdev);
1573
1574 return err;
1575}
1576
1577static int remove_remote_oob_data(struct sock *sk, u16 index,
1578 unsigned char *data, u16 len)
1579{
1580 struct hci_dev *hdev;
1581 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1582 int err;
1583
1584 BT_DBG("hci%u ", index);
1585
1586 if (len != sizeof(*cp))
1587 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1588 EINVAL);
1589
1590 hdev = hci_dev_get(index);
1591 if (!hdev)
1592 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1593 ENODEV);
1594
Andre Guedes8c156c32011-07-07 10:30:36 -03001595 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001596
1597 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1598 if (err < 0)
1599 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1600 -err);
1601 else
1602 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1603 NULL, 0);
1604
Andre Guedes8c156c32011-07-07 10:30:36 -03001605 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001606 hci_dev_put(hdev);
1607
1608 return err;
1609}
1610
Johan Hedberg14a53662011-04-27 10:29:56 -04001611static int start_discovery(struct sock *sk, u16 index)
1612{
Johan Hedberg14a53662011-04-27 10:29:56 -04001613 struct pending_cmd *cmd;
1614 struct hci_dev *hdev;
1615 int err;
1616
1617 BT_DBG("hci%u", index);
1618
1619 hdev = hci_dev_get(index);
1620 if (!hdev)
1621 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1622
1623 hci_dev_lock_bh(hdev);
1624
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001625 if (!test_bit(HCI_UP, &hdev->flags)) {
1626 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1627 goto failed;
1628 }
1629
Johan Hedberg14a53662011-04-27 10:29:56 -04001630 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1631 if (!cmd) {
1632 err = -ENOMEM;
1633 goto failed;
1634 }
1635
Andre Guedes2519a1f2011-11-07 11:45:24 -03001636 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001637 if (err < 0)
1638 mgmt_pending_remove(cmd);
1639
1640failed:
1641 hci_dev_unlock_bh(hdev);
1642 hci_dev_put(hdev);
1643
1644 return err;
1645}
1646
1647static int stop_discovery(struct sock *sk, u16 index)
1648{
1649 struct hci_dev *hdev;
1650 struct pending_cmd *cmd;
1651 int err;
1652
1653 BT_DBG("hci%u", index);
1654
1655 hdev = hci_dev_get(index);
1656 if (!hdev)
1657 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1658
1659 hci_dev_lock_bh(hdev);
1660
1661 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1662 if (!cmd) {
1663 err = -ENOMEM;
1664 goto failed;
1665 }
1666
Andre Guedes023d50492011-11-04 14:16:52 -03001667 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001668 if (err < 0)
1669 mgmt_pending_remove(cmd);
1670
1671failed:
1672 hci_dev_unlock_bh(hdev);
1673 hci_dev_put(hdev);
1674
1675 return err;
1676}
1677
Antti Julku7fbec222011-06-15 12:01:15 +03001678static int block_device(struct sock *sk, u16 index, unsigned char *data,
1679 u16 len)
1680{
1681 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001682 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001683 int err;
1684
1685 BT_DBG("hci%u", index);
1686
Antti Julku7fbec222011-06-15 12:01:15 +03001687 if (len != sizeof(*cp))
1688 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1689 EINVAL);
1690
1691 hdev = hci_dev_get(index);
1692 if (!hdev)
1693 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1694 ENODEV);
1695
Antti Julku5e762442011-08-25 16:48:02 +03001696 hci_dev_lock_bh(hdev);
1697
Antti Julku7fbec222011-06-15 12:01:15 +03001698 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001699 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
Antti Julku5e762442011-08-25 16:48:02 +03001705 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001706 hci_dev_put(hdev);
1707
1708 return err;
1709}
1710
1711static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1712 u16 len)
1713{
1714 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001715 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001716 int err;
1717
1718 BT_DBG("hci%u", index);
1719
Antti Julku7fbec222011-06-15 12:01:15 +03001720 if (len != sizeof(*cp))
1721 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1722 EINVAL);
1723
1724 hdev = hci_dev_get(index);
1725 if (!hdev)
1726 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1727 ENODEV);
1728
Antti Julku5e762442011-08-25 16:48:02 +03001729 hci_dev_lock_bh(hdev);
1730
Antti Julku7fbec222011-06-15 12:01:15 +03001731 err = hci_blacklist_del(hdev, &cp->bdaddr);
1732
1733 if (err < 0)
1734 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1735 else
1736 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1737 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001738
Antti Julku5e762442011-08-25 16:48:02 +03001739 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001740 hci_dev_put(hdev);
1741
1742 return err;
1743}
1744
Antti Julkuf6422ec2011-06-22 13:11:56 +03001745static int set_fast_connectable(struct sock *sk, u16 index,
1746 unsigned char *data, u16 len)
1747{
1748 struct hci_dev *hdev;
1749 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1750 struct hci_cp_write_page_scan_activity acp;
1751 u8 type;
1752 int err;
1753
1754 BT_DBG("hci%u", index);
1755
1756 if (len != sizeof(*cp))
1757 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1758 EINVAL);
1759
1760 hdev = hci_dev_get(index);
1761 if (!hdev)
1762 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1763 ENODEV);
1764
1765 hci_dev_lock(hdev);
1766
1767 if (cp->enable) {
1768 type = PAGE_SCAN_TYPE_INTERLACED;
1769 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1770 } else {
1771 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1772 acp.interval = 0x0800; /* default 1.28 sec page scan */
1773 }
1774
1775 acp.window = 0x0012; /* default 11.25 msec page scan window */
1776
1777 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1778 sizeof(acp), &acp);
1779 if (err < 0) {
1780 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1781 -err);
1782 goto done;
1783 }
1784
1785 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1786 if (err < 0) {
1787 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1788 -err);
1789 goto done;
1790 }
1791
1792 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1793 NULL, 0);
1794done:
1795 hci_dev_unlock(hdev);
1796 hci_dev_put(hdev);
1797
1798 return err;
1799}
1800
Johan Hedberg03811012010-12-08 00:21:06 +02001801int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1802{
1803 unsigned char *buf;
1804 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001805 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001806 int err;
1807
1808 BT_DBG("got %zu bytes", msglen);
1809
1810 if (msglen < sizeof(*hdr))
1811 return -EINVAL;
1812
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001813 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001814 if (!buf)
1815 return -ENOMEM;
1816
1817 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1818 err = -EFAULT;
1819 goto done;
1820 }
1821
1822 hdr = (struct mgmt_hdr *) buf;
1823 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001824 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001825 len = get_unaligned_le16(&hdr->len);
1826
1827 if (len != msglen - sizeof(*hdr)) {
1828 err = -EINVAL;
1829 goto done;
1830 }
1831
1832 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001833 case MGMT_OP_READ_VERSION:
1834 err = read_version(sk);
1835 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001836 case MGMT_OP_READ_INDEX_LIST:
1837 err = read_index_list(sk);
1838 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001839 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001840 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001841 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001842 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001843 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001844 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001845 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001847 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001848 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001850 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001851 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001852 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001853 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001854 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001855 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001856 break;
1857 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001858 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001859 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001860 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001861 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001862 break;
1863 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001865 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001866 case MGMT_OP_LOAD_LINK_KEYS:
1867 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001868 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001869 case MGMT_OP_REMOVE_KEYS:
1870 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001871 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001872 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001874 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001875 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001876 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001877 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001879 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001880 break;
1881 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001882 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001883 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001884 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001886 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001890 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001892 break;
1893 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001895 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001896 case MGMT_OP_SET_LOCAL_NAME:
1897 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1898 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001899 case MGMT_OP_READ_LOCAL_OOB_DATA:
1900 err = read_local_oob_data(sk, index);
1901 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001902 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1903 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1904 break;
1905 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1906 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1907 len);
1908 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001909 case MGMT_OP_START_DISCOVERY:
1910 err = start_discovery(sk, index);
1911 break;
1912 case MGMT_OP_STOP_DISCOVERY:
1913 err = stop_discovery(sk, index);
1914 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001915 case MGMT_OP_BLOCK_DEVICE:
1916 err = block_device(sk, index, buf + sizeof(*hdr), len);
1917 break;
1918 case MGMT_OP_UNBLOCK_DEVICE:
1919 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1920 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001921 case MGMT_OP_SET_FAST_CONNECTABLE:
1922 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1923 len);
1924 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001925 default:
1926 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001927 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001928 break;
1929 }
1930
Johan Hedberge41d8b42010-12-13 21:07:03 +02001931 if (err < 0)
1932 goto done;
1933
Johan Hedberg03811012010-12-08 00:21:06 +02001934 err = msglen;
1935
1936done:
1937 kfree(buf);
1938 return err;
1939}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001940
Johan Hedbergb24752f2011-11-03 14:40:33 +02001941static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1942{
1943 u8 *status = data;
1944
1945 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1946 mgmt_pending_remove(cmd);
1947}
1948
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001949int mgmt_index_added(u16 index)
1950{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001951 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001952}
1953
1954int mgmt_index_removed(u16 index)
1955{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001956 u8 status = ENODEV;
1957
1958 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1959
Szymon Janc4e51eae2011-02-25 19:05:48 +01001960 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001961}
1962
Johan Hedberg73f22f62010-12-29 16:00:25 +02001963struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001964 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001965 struct sock *sk;
1966};
1967
Johan Hedberg72a734e2010-12-30 00:38:22 +02001968static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001969{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001970 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001971 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001972
Johan Hedberg72a734e2010-12-30 00:38:22 +02001973 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001974 return;
1975
Johan Hedberg053f0212011-01-26 13:07:10 +02001976 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001977
1978 list_del(&cmd->list);
1979
1980 if (match->sk == NULL) {
1981 match->sk = cmd->sk;
1982 sock_hold(match->sk);
1983 }
1984
1985 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001986}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001987
1988int mgmt_powered(u16 index, u8 powered)
1989{
Johan Hedberg72a734e2010-12-30 00:38:22 +02001990 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001991 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001992 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02001993
Johan Hedberg72a734e2010-12-30 00:38:22 +02001994 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02001995
Johan Hedbergb24752f2011-11-03 14:40:33 +02001996 if (!powered) {
1997 u8 status = ENETDOWN;
1998 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1999 }
2000
Johan Hedberg72a734e2010-12-30 00:38:22 +02002001 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002002
Szymon Janc4e51eae2011-02-25 19:05:48 +01002003 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002004
2005 if (match.sk)
2006 sock_put(match.sk);
2007
2008 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002009}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002010
Johan Hedberg73f22f62010-12-29 16:00:25 +02002011int mgmt_discoverable(u16 index, u8 discoverable)
2012{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002013 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002014 struct cmd_lookup match = { discoverable, NULL };
2015 int ret;
2016
Szymon Jancb8534e02011-03-01 16:55:34 +01002017 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002018
Johan Hedberg72a734e2010-12-30 00:38:22 +02002019 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002020
Szymon Janc4e51eae2011-02-25 19:05:48 +01002021 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2022 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002023
2024 if (match.sk)
2025 sock_put(match.sk);
2026
2027 return ret;
2028}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002029
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002030int mgmt_connectable(u16 index, u8 connectable)
2031{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002032 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002033 struct cmd_lookup match = { connectable, NULL };
2034 int ret;
2035
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002037
Johan Hedberg72a734e2010-12-30 00:38:22 +02002038 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002039
Szymon Janc4e51eae2011-02-25 19:05:48 +01002040 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002041
2042 if (match.sk)
2043 sock_put(match.sk);
2044
2045 return ret;
2046}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002047
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002048int mgmt_write_scan_failed(u16 index, u8 scan, u8 status)
2049{
2050 if (scan & SCAN_PAGE)
2051 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index,
2052 cmd_status_rsp, &status);
2053
2054 if (scan & SCAN_INQUIRY)
2055 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
2056 cmd_status_rsp, &status);
2057
2058 return 0;
2059}
2060
Johan Hedberg86742e12011-11-07 23:13:38 +02002061int mgmt_new_link_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002062{
Johan Hedberg86742e12011-11-07 23:13:38 +02002063 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002065 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002066
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002067 ev.store_hint = persistent;
2068 bacpy(&ev.key.bdaddr, &key->bdaddr);
2069 ev.key.type = key->type;
2070 memcpy(ev.key.val, key->val, 16);
2071 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002072
Johan Hedberg86742e12011-11-07 23:13:38 +02002073 return mgmt_event(MGMT_EV_NEW_LINK_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002074}
Johan Hedbergf7520542011-01-20 12:34:39 +02002075
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002076int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002077{
2078 struct mgmt_ev_connected ev;
2079
Johan Hedbergf7520542011-01-20 12:34:39 +02002080 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002081 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002082
Szymon Janc4e51eae2011-02-25 19:05:48 +01002083 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002084}
2085
Johan Hedberg8962ee72011-01-20 12:40:27 +02002086static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2087{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002088 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002089 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002090 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091
Johan Hedberga38528f2011-01-22 06:46:43 +02002092 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002093
Szymon Janc4e51eae2011-02-25 19:05:48 +01002094 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002095
2096 *sk = cmd->sk;
2097 sock_hold(*sk);
2098
Johan Hedberga664b5b2011-02-19 12:06:02 -03002099 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002100}
2101
Johan Hedbergf7520542011-01-20 12:34:39 +02002102int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2103{
2104 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002105 struct sock *sk = NULL;
2106 int err;
2107
2108 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002109
Johan Hedbergf7520542011-01-20 12:34:39 +02002110 bacpy(&ev.bdaddr, bdaddr);
2111
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113
2114 if (sk)
2115 sock_put(sk);
2116
2117 return err;
2118}
2119
2120int mgmt_disconnect_failed(u16 index)
2121{
2122 struct pending_cmd *cmd;
2123 int err;
2124
2125 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2126 if (!cmd)
2127 return -ENOENT;
2128
Szymon Janc4e51eae2011-02-25 19:05:48 +01002129 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002130
Johan Hedberga664b5b2011-02-19 12:06:02 -03002131 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002132
2133 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002134}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002135
2136int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2137{
2138 struct mgmt_ev_connect_failed ev;
2139
Johan Hedberg17d5c042011-01-22 06:09:08 +02002140 bacpy(&ev.bdaddr, bdaddr);
2141 ev.status = status;
2142
Szymon Janc4e51eae2011-02-25 19:05:48 +01002143 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002144}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002146int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147{
2148 struct mgmt_ev_pin_code_request ev;
2149
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002151 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002152
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2154 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002155}
2156
2157int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2158{
2159 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002160 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002161 int err;
2162
2163 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2164 if (!cmd)
2165 return -ENOENT;
2166
Johan Hedbergac56fb12011-02-19 12:05:59 -03002167 bacpy(&rp.bdaddr, bdaddr);
2168 rp.status = status;
2169
Szymon Janc4e51eae2011-02-25 19:05:48 +01002170 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2171 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172
Johan Hedberga664b5b2011-02-19 12:06:02 -03002173 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174
2175 return err;
2176}
2177
2178int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2179{
2180 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002181 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182 int err;
2183
2184 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2185 if (!cmd)
2186 return -ENOENT;
2187
Johan Hedbergac56fb12011-02-19 12:05:59 -03002188 bacpy(&rp.bdaddr, bdaddr);
2189 rp.status = status;
2190
Szymon Janc4e51eae2011-02-25 19:05:48 +01002191 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2192 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002193
Johan Hedberga664b5b2011-02-19 12:06:02 -03002194 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002195
2196 return err;
2197}
Johan Hedberga5c29682011-02-19 12:05:57 -03002198
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002199int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2200 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002201{
2202 struct mgmt_ev_user_confirm_request ev;
2203
2204 BT_DBG("hci%u", index);
2205
Johan Hedberga5c29682011-02-19 12:05:57 -03002206 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002207 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002208 put_unaligned_le32(value, &ev.value);
2209
Szymon Janc4e51eae2011-02-25 19:05:48 +01002210 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2211 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002212}
2213
2214static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2215 u8 opcode)
2216{
2217 struct pending_cmd *cmd;
2218 struct mgmt_rp_user_confirm_reply rp;
2219 int err;
2220
2221 cmd = mgmt_pending_find(opcode, index);
2222 if (!cmd)
2223 return -ENOENT;
2224
Johan Hedberga5c29682011-02-19 12:05:57 -03002225 bacpy(&rp.bdaddr, bdaddr);
2226 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002227 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002228
Johan Hedberga664b5b2011-02-19 12:06:02 -03002229 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002230
2231 return err;
2232}
2233
2234int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2235{
2236 return confirm_reply_complete(index, bdaddr, status,
2237 MGMT_OP_USER_CONFIRM_REPLY);
2238}
2239
Szymon Jancb8534e02011-03-01 16:55:34 +01002240int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002241{
2242 return confirm_reply_complete(index, bdaddr, status,
2243 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2244}
Johan Hedberg2a611692011-02-19 12:06:00 -03002245
2246int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2247{
2248 struct mgmt_ev_auth_failed ev;
2249
Johan Hedberg2a611692011-02-19 12:06:00 -03002250 bacpy(&ev.bdaddr, bdaddr);
2251 ev.status = status;
2252
Szymon Janc4e51eae2011-02-25 19:05:48 +01002253 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002254}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002255
2256int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2257{
2258 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002259 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002260 struct mgmt_cp_set_local_name ev;
2261 int err;
2262
2263 memset(&ev, 0, sizeof(ev));
2264 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2265
2266 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2267 if (!cmd)
2268 goto send_event;
2269
2270 if (status) {
2271 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2272 goto failed;
2273 }
2274
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002275 hdev = hci_dev_get(index);
2276 if (hdev) {
2277 hci_dev_lock_bh(hdev);
2278 update_eir(hdev);
2279 hci_dev_unlock_bh(hdev);
2280 hci_dev_put(hdev);
2281 }
2282
Johan Hedbergb312b1612011-03-16 14:29:37 +02002283 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2284 sizeof(ev));
2285 if (err < 0)
2286 goto failed;
2287
2288send_event:
2289 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2290 cmd ? cmd->sk : NULL);
2291
2292failed:
2293 if (cmd)
2294 mgmt_pending_remove(cmd);
2295 return err;
2296}
Szymon Jancc35938b2011-03-22 13:12:21 +01002297
2298int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2299 u8 status)
2300{
2301 struct pending_cmd *cmd;
2302 int err;
2303
2304 BT_DBG("hci%u status %u", index, status);
2305
2306 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2307 if (!cmd)
2308 return -ENOENT;
2309
2310 if (status) {
2311 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2312 EIO);
2313 } else {
2314 struct mgmt_rp_read_local_oob_data rp;
2315
2316 memcpy(rp.hash, hash, sizeof(rp.hash));
2317 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2318
2319 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2320 &rp, sizeof(rp));
2321 }
2322
2323 mgmt_pending_remove(cmd);
2324
2325 return err;
2326}
Johan Hedberge17acd42011-03-30 23:57:16 +03002327
2328int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2329 u8 *eir)
2330{
2331 struct mgmt_ev_device_found ev;
2332
2333 memset(&ev, 0, sizeof(ev));
2334
2335 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002336 ev.rssi = rssi;
2337
2338 if (eir)
2339 memcpy(ev.eir, eir, sizeof(ev.eir));
2340
Andre Guedesf8523592011-09-09 18:56:26 -03002341 if (dev_class)
2342 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2343
Johan Hedberge17acd42011-03-30 23:57:16 +03002344 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2345}
Johan Hedberga88a9652011-03-30 13:18:12 +03002346
2347int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2348{
2349 struct mgmt_ev_remote_name ev;
2350
2351 memset(&ev, 0, sizeof(ev));
2352
2353 bacpy(&ev.bdaddr, bdaddr);
2354 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2355
2356 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2357}
Johan Hedberg314b2382011-04-27 10:29:57 -04002358
Johan Hedberg164a6e72011-11-01 17:06:44 +02002359int mgmt_inquiry_failed(u16 index, u8 status)
2360{
2361 struct pending_cmd *cmd;
2362 int err;
2363
2364 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2365 if (!cmd)
2366 return -ENOENT;
2367
2368 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2369 mgmt_pending_remove(cmd);
2370
2371 return err;
2372}
2373
Johan Hedberg314b2382011-04-27 10:29:57 -04002374int mgmt_discovering(u16 index, u8 discovering)
2375{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002376 struct pending_cmd *cmd;
2377
2378 if (discovering)
2379 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2380 else
2381 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2382
2383 if (cmd != NULL) {
2384 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2385 mgmt_pending_remove(cmd);
2386 }
2387
Johan Hedberg314b2382011-04-27 10:29:57 -04002388 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2389 sizeof(discovering), NULL);
2390}
Antti Julku5e762442011-08-25 16:48:02 +03002391
2392int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2393{
2394 struct pending_cmd *cmd;
2395 struct mgmt_ev_device_blocked ev;
2396
2397 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2398
2399 bacpy(&ev.bdaddr, bdaddr);
2400
2401 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2402 cmd ? cmd->sk : NULL);
2403}
2404
2405int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2406{
2407 struct pending_cmd *cmd;
2408 struct mgmt_ev_device_unblocked ev;
2409
2410 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2411
2412 bacpy(&ev.bdaddr, bdaddr);
2413
2414 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2415 cmd ? cmd->sk : NULL);
2416}